Merge "GpsLocationProvider: Do our work in a Handler running in a separate thread."
diff --git a/api/current.xml b/api/current.xml
index 9dc2218..58ce3ee 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26873,11 +26873,22 @@
  visibility="public"
 >
 </field>
+<field name="PASSWORD_QUALITY_ALPHABETIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="262144"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="PASSWORD_QUALITY_ALPHANUMERIC"
  type="int"
  transient="false"
  volatile="false"
- value="196608"
+ value="327680"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -80658,6 +80669,19 @@
 <parameter name="l" type="android.media.AudioManager.OnAudioFocusChangeListener">
 </parameter>
 </method>
+<method name="registerMediaButtonEventReceiver"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="eventReceiver" type="android.content.ComponentName">
+</parameter>
+</method>
 <method name="requestAudioFocus"
  return="int"
  abstract="false"
@@ -80917,6 +80941,19 @@
 <parameter name="l" type="android.media.AudioManager.OnAudioFocusChangeListener">
 </parameter>
 </method>
+<method name="unregisterMediaButtonEventReceiver"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="eventReceiver" type="android.content.ComponentName">
+</parameter>
+</method>
 <field name="ACTION_AUDIO_BECOMING_NOISY"
  type="java.lang.String"
  transient="false"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index cfc2e75..659d70f 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -92,11 +92,6 @@
             return;
         }
 
-        if ("mountsd".equals(op)) {
-            runMountSd();
-            return;
-        }
-
         if ("uninstall".equals(op)) {
             runUninstall();
             return;
@@ -646,37 +641,6 @@
         }
     }
 
-    private void runMountSd() {
-        String opt;
-        boolean mount = false;
-        while ((opt=nextOption()) != null) {
-            if (opt.equals("-m")) {
-                String mountStr = nextOptionData();
-                if (mountStr == null) {
-                    System.err.println("Error: no value specified for -m");
-                    showUsage();
-                    return;
-                }
-                if ("true".equalsIgnoreCase(mountStr)) {
-                    mount = true;
-                } else if ("false".equalsIgnoreCase(mountStr)) {
-                    mount = false;
-                } else {
-                    System.err.println("Error: no value specified for -m");
-                    showUsage();
-                    return;
-                }
-            }
-        }
-
-        try {
-            mPm.updateExternalMediaStatus(mount);
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-        }
-    }
-
     class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
         boolean finished;
         boolean result;
@@ -866,7 +830,6 @@
         System.err.println("       pm path PACKAGE");
         System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
         System.err.println("       pm uninstall [-k] PACKAGE");
-        System.err.println("       pm mountsd [-m true/false]");
         System.err.println("       pm enable PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable PACKAGE_OR_COMPONENT");
         System.err.println("");
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6d5686a..596ca9d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -980,10 +980,11 @@
             return true;
         }
 
-        case KILL_PIDS_FOR_MEMORY_TRANSACTION: {
+        case KILL_PIDS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int[] pids = data.createIntArray();
-            boolean res = killPidsForMemory(pids);
+            String reason = data.readString();
+            boolean res = killPids(pids, reason);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -2393,12 +2394,13 @@
         mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
         data.recycle();
     }
-    public boolean killPidsForMemory(int[] pids) throws RemoteException {
+    public boolean killPids(int[] pids, String reason) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeIntArray(pids);
-        mRemote.transact(KILL_PIDS_FOR_MEMORY_TRANSACTION, data, reply, 0);
+        data.writeString(reason);
+        mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0);
         boolean res = reply.readInt() != 0;
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 14571de..30feae1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -241,7 +241,7 @@
     
     public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
     
-    public boolean killPidsForMemory(int[] pids) throws RemoteException;
+    public boolean killPids(int[] pids, String reason) throws RemoteException;
     
     public void reportPss(IApplicationThread caller, int pss) throws RemoteException;
     
@@ -476,7 +476,7 @@
     int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
     int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
     int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
-    int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
+    int KILL_PIDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
     int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
     int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
     int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 2d9b415..35e7ee6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,7 +20,6 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.app.admin.IDevicePolicyManager.Stub;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -192,11 +191,19 @@
     
     /**
      * Constant for {@link #setPasswordQuality}: the user must have entered a
+     * password containing at least alphabetic (or other symbol) characters.
+     * Note that quality constants are ordered so that higher values are more
+     * restrictive.
+     */
+    public static final int PASSWORD_QUALITY_ALPHABETIC = 0x40000;
+    
+    /**
+     * Constant for {@link #setPasswordQuality}: the user must have entered a
      * password containing at least <em>both></em> numeric <em>and</em>
-     * alphabeter (or other symbol) characters.  Note that quality constants are
+     * alphabetic (or other symbol) characters.  Note that quality constants are
      * ordered so that higher values are more restrictive.
      */
-    public static final int PASSWORD_QUALITY_ALPHANUMERIC = 0x30000;
+    public static final int PASSWORD_QUALITY_ALPHANUMERIC = 0x50000;
     
     /**
      * Called by an application that is administering the device to set the
@@ -219,7 +226,8 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param quality The new desired quality.  One of
      * {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING},
-     * {@link #PASSWORD_QUALITY_NUMERIC}, or {@link #PASSWORD_QUALITY_ALPHANUMERIC}.
+     * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC},
+     * or {@link #PASSWORD_QUALITY_ALPHANUMERIC}.
      */
     public void setPasswordQuality(ComponentName admin, int quality) {
         if (mService != null) {
@@ -257,7 +265,8 @@
      * take place immediately.  To prompt the user for a new password, use
      * {@link #ACTION_SET_NEW_PASSWORD} after setting this value.  This
      * constraint is only imposed if the administrator has also requested either
-     * {@link #PASSWORD_QUALITY_NUMERIC} or {@link #PASSWORD_QUALITY_ALPHANUMERIC}
+     * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC},
+     * or {@link #PASSWORD_QUALITY_ALPHANUMERIC}
      * with {@link #setPasswordQuality}.
      * 
      * <p>The calling device admin must have requested
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 399a87d..c638d04 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -309,7 +309,7 @@
      * MountService uses this to call into the package manager to update
      * status of sdcard.
      */
-    boolean updateExternalMediaStatus(boolean mounted);
+    void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
 
     String nextPackageToClean(String lastPackage);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bbf4ca1..0318b6c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -233,7 +233,7 @@
     /**
      * Flag parameter for {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} to
      * indicate that this package should be installed as forward locked, i.e. only the app itself
-     * should have access to it's code and non-resource assets.
+     * should have access to its code and non-resource assets.
      * @hide
      */
     public static final int INSTALL_FORWARD_LOCK = 0x00000001;
diff --git a/core/java/android/database/MergeCursor.java b/core/java/android/database/MergeCursor.java
index 7e91159..722d707 100644
--- a/core/java/android/database/MergeCursor.java
+++ b/core/java/android/database/MergeCursor.java
@@ -185,6 +185,7 @@
                 mCursors[i].deactivate();
             }
         }
+        super.deactivate();
     }
 
     @Override
@@ -194,6 +195,7 @@
             if (mCursors[i] == null) continue;
             mCursors[i].close();
         }
+        super.close();
     }
 
     @Override
diff --git a/core/java/android/hardware/GeomagneticField.java b/core/java/android/hardware/GeomagneticField.java
index b4c04b1..96fbe77 100644
--- a/core/java/android/hardware/GeomagneticField.java
+++ b/core/java/android/hardware/GeomagneticField.java
@@ -26,8 +26,9 @@
  * <p>This uses the World Magnetic Model produced by the United States National
  * Geospatial-Intelligence Agency.  More details about the model can be found at
  * <a href="http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml">http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml</a>.
- * This class currently uses WMM-2005 which is valid until 2010, but should
- * produce acceptable results for several years after that.
+ * This class currently uses WMM-2010 which is valid until 2015, but should
+ * produce acceptable results for several years after that. Future versions of
+ * Android may use a newer version of the model.
  */
 public class GeomagneticField {
     // The magnetic field at a given point, in nonoteslas in geodetic
@@ -43,75 +44,73 @@
 
     // Constants from WGS84 (the coordinate system used by GPS)
     static private final float EARTH_SEMI_MAJOR_AXIS_KM = 6378.137f;
-    static private final float EARTH_SEMI_MINOR_AXIS_KM = 6356.7523f;
+    static private final float EARTH_SEMI_MINOR_AXIS_KM = 6356.7523142f;
     static private final float EARTH_REFERENCE_RADIUS_KM = 6371.2f;
 
     // These coefficients and the formulae used below are from:
-    // NOAA Technical Report: The US/UK World Magnetic Model for 2005-2010
+    // NOAA Technical Report: The US/UK World Magnetic Model for 2010-2015
     static private final float[][] G_COEFF = new float[][] {
-        { 0f },
-        { -29556.8f, -1671.7f },
-        { -2340.6f, 3046.9f, 1657.0f },
-        { 1335.4f, -2305.1f, 1246.7f, 674.0f },
-        { 919.8f, 798.1f, 211.3f, -379.4f, 100.0f },
-        { -227.4f, 354.6f, 208.7f, -136.5f, -168.3f, -14.1f },
-        { 73.2f, 69.7f, 76.7f, -151.2f, -14.9f, 14.6f, -86.3f },
-        { 80.1f, -74.5f, -1.4f, 38.5f, 12.4f, 9.5f, 5.7f, 1.8f },
-        { 24.9f, 7.7f, -11.6f, -6.9f, -18.2f, 10.0f, 9.2f, -11.6f, -5.2f },
-        { 5.6f, 9.9f, 3.5f, -7.0f, 5.1f, -10.8f, -1.3f, 8.8f, -6.7f, -9.1f },
-        { -2.3f, -6.3f, 1.6f, -2.6f, 0.0f, 3.1f, 0.4f, 2.1f, 3.9f, -0.1f, -2.3f },
-        { 2.8f, -1.6f, -1.7f, 1.7f, -0.1f, 0.1f, -0.7f, 0.7f, 1.8f, 0.0f, 1.1f, 4.1f },
-        { -2.4f, -0.4f, 0.2f, 0.8f, -0.3f, 1.1f, -0.5f, 0.4f, -0.3f, -0.3f, -0.1f,
-          -0.3f, -0.1f } };
+        { 0.0f },
+        { -29496.6f, -1586.3f },
+        { -2396.6f, 3026.1f, 1668.6f },
+        { 1340.1f, -2326.2f, 1231.9f, 634.0f },
+        { 912.6f, 808.9f, 166.7f, -357.1f, 89.4f },
+        { -230.9f, 357.2f, 200.3f, -141.1f, -163.0f, -7.8f },
+        { 72.8f, 68.6f, 76.0f, -141.4f, -22.8f, 13.2f, -77.9f },
+        { 80.5f, -75.1f, -4.7f, 45.3f, 13.9f, 10.4f, 1.7f, 4.9f },
+        { 24.4f, 8.1f, -14.5f, -5.6f, -19.3f, 11.5f, 10.9f, -14.1f, -3.7f },
+        { 5.4f, 9.4f, 3.4f, -5.2f, 3.1f, -12.4f, -0.7f, 8.4f, -8.5f, -10.1f },
+        { -2.0f, -6.3f, 0.9f, -1.1f, -0.2f, 2.5f, -0.3f, 2.2f, 3.1f, -1.0f, -2.8f },
+        { 3.0f, -1.5f, -2.1f, 1.7f, -0.5f, 0.5f, -0.8f, 0.4f, 1.8f, 0.1f, 0.7f, 3.8f },
+        { -2.2f, -0.2f, 0.3f, 1.0f, -0.6f, 0.9f, -0.1f, 0.5f, -0.4f, -0.4f, 0.2f, -0.8f, 0.0f } };
 
     static private final float[][] H_COEFF = new float[][] {
-        { 0f },
-        { 0.0f, 5079.8f },
-        { 0.0f, -2594.7f, -516.7f },
-        { 0.0f, -199.9f, 269.3f, -524.2f },
-        { 0.0f, 281.5f, -226.0f, 145.8f, -304.7f },
-        { 0.0f, 42.4f, 179.8f, -123.0f, -19.5f, 103.6f },
-        { 0.0f, -20.3f, 54.7f, 63.6f, -63.4f, -0.1f, 50.4f },
-        { 0.0f, -61.5f, -22.4f, 7.2f, 25.4f, 11.0f, -26.4f, -5.1f },
-        { 0.0f, 11.2f, -21.0f, 9.6f, -19.8f, 16.1f, 7.7f, -12.9f, -0.2f },
-        { 0.0f, -20.1f, 12.9f, 12.6f, -6.7f, -8.1f, 8.0f, 2.9f, -7.9f, 6.0f },
-        { 0.0f, 2.4f, 0.2f, 4.4f, 4.8f, -6.5f, -1.1f, -3.4f, -0.8f, -2.3f, -7.9f },
-        { 0.0f, 0.3f, 1.2f, -0.8f, -2.5f, 0.9f, -0.6f, -2.7f, -0.9f, -1.3f, -2.0f, -1.2f },
-        { 0.0f, -0.4f, 0.3f, 2.4f, -2.6f, 0.6f, 0.3f, 0.0f, 0.0f, 0.3f, -0.9f, -0.4f,
-          0.8f } };
+        { 0.0f },
+        { 0.0f, 4944.4f },
+        { 0.0f, -2707.7f, -576.1f },
+        { 0.0f, -160.2f, 251.9f, -536.6f },
+        { 0.0f, 286.4f, -211.2f, 164.3f, -309.1f },
+        { 0.0f, 44.6f, 188.9f, -118.2f, 0.0f, 100.9f },
+        { 0.0f, -20.8f, 44.1f, 61.5f, -66.3f, 3.1f, 55.0f },
+        { 0.0f, -57.9f, -21.1f, 6.5f, 24.9f, 7.0f, -27.7f, -3.3f },
+        { 0.0f, 11.0f, -20.0f, 11.9f, -17.4f, 16.7f, 7.0f, -10.8f, 1.7f },
+        { 0.0f, -20.5f, 11.5f, 12.8f, -7.2f, -7.4f, 8.0f, 2.1f, -6.1f, 7.0f },
+        { 0.0f, 2.8f, -0.1f, 4.7f, 4.4f, -7.2f, -1.0f, -3.9f, -2.0f, -2.0f, -8.3f },
+        { 0.0f, 0.2f, 1.7f, -0.6f, -1.8f, 0.9f, -0.4f, -2.5f, -1.3f, -2.1f, -1.9f, -1.8f },
+        { 0.0f, -0.9f, 0.3f, 2.1f, -2.5f, 0.5f, 0.6f, 0.0f, 0.1f, 0.3f, -0.9f, -0.2f, 0.9f } };
 
     static private final float[][] DELTA_G = new float[][] {
-        { 0f },
-        { 8.0f, 10.6f },
-        { -15.1f, -7.8f, -0.8f },
-        { 0.4f, -2.6f, -1.2f, -6.5f },
-        { -2.5f, 2.8f, -7.0f, 6.2f, -3.8f },
-        { -2.8f, 0.7f, -3.2f, -1.1f, 0.1f, -0.8f },
-        { -0.7f, 0.4f, -0.3f, 2.3f, -2.1f, -0.6f, 1.4f },
-        { 0.2f, -0.1f, -0.3f, 1.1f, 0.6f, 0.5f, -0.4f, 0.6f },
-        { 0.1f, 0.3f, -0.4f, 0.3f, -0.3f, 0.2f, 0.4f, -0.7f, 0.4f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
+        { 0.0f },
+        { 11.6f, 16.5f },
+        { -12.1f, -4.4f, 1.9f },
+        { 0.4f, -4.1f, -2.9f, -7.7f },
+        { -1.8f, 2.3f, -8.7f, 4.6f, -2.1f },
+        { -1.0f, 0.6f, -1.8f, -1.0f, 0.9f, 1.0f },
+        { -0.2f, -0.2f, -0.1f, 2.0f, -1.7f, -0.3f, 1.7f },
+        { 0.1f, -0.1f, -0.6f, 1.3f, 0.4f, 0.3f, -0.7f, 0.6f },
+        { -0.1f, 0.1f, -0.6f, 0.2f, -0.2f, 0.3f, 0.3f, -0.6f, 0.2f },
+        { 0.0f, -0.1f, 0.0f, 0.3f, -0.4f, -0.3f, 0.1f, -0.1f, -0.4f, -0.2f },
+        { 0.0f, 0.0f, -0.1f, 0.2f, 0.0f, -0.1f, -0.2f, 0.0f, -0.1f, -0.2f, -0.2f },
+        { 0.0f, 0.0f, 0.0f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.1f, 0.0f },
+        { 0.0f, 0.0f, 0.1f, 0.1f, -0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.1f, 0.1f } };
 
     static private final float[][] DELTA_H = new float[][] {
-        { 0f },
-        { 0.0f, -20.9f },
-        { 0.0f, -23.2f, -14.6f },
-        { 0.0f, 5.0f, -7.0f, -0.6f },
-        { 0.0f, 2.2f, 1.6f, 5.8f, 0.1f },
-        { 0.0f, 0.0f, 1.7f, 2.1f, 4.8f, -1.1f },
-        { 0.0f, -0.6f, -1.9f, -0.4f, -0.5f, -0.3f, 0.7f },
-        { 0.0f, 0.6f, 0.4f, 0.2f, 0.3f, -0.8f, -0.2f, 0.1f },
-        { 0.0f, -0.2f, 0.1f, 0.3f, 0.4f, 0.1f, -0.2f, 0.4f, 0.4f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
-        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
+        { 0.0f },
+        { 0.0f, -25.9f },
+        { 0.0f, -22.5f, -11.8f },
+        { 0.0f, 7.3f, -3.9f, -2.6f },
+        { 0.0f, 1.1f, 2.7f, 3.9f, -0.8f },
+        { 0.0f, 0.4f, 1.8f, 1.2f, 4.0f, -0.6f },
+        { 0.0f, -0.2f, -2.1f, -0.4f, -0.6f, 0.5f, 0.9f },
+        { 0.0f, 0.7f, 0.3f, -0.1f, -0.1f, -0.8f, -0.3f, 0.3f },
+        { 0.0f, -0.1f, 0.2f, 0.4f, 0.4f, 0.1f, -0.1f, 0.4f, 0.3f },
+        { 0.0f, 0.0f, -0.2f, 0.0f, -0.1f, 0.1f, 0.0f, -0.2f, 0.3f, 0.2f },
+        { 0.0f, 0.1f, -0.1f, 0.0f, -0.1f, -0.1f, 0.0f, -0.1f, -0.2f, 0.0f, -0.1f },
+        { 0.0f, 0.0f, 0.1f, 0.0f, 0.1f, 0.0f, 0.1f, 0.0f, -0.1f, -0.1f, 0.0f, -0.1f },
+        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
 
     static private final long BASE_TIME =
-        new GregorianCalendar(2005, 1, 1).getTimeInMillis();
+        new GregorianCalendar(2010, 1, 1).getTimeInMillis();
 
     // The ratio between the Gauss-normalized associated Legendre functions and
     // the Schmid quasi-normalized ones. Compute these once staticly since they
@@ -191,7 +190,7 @@
         // We now compute the magnetic field strength given the geocentric
         // location. The magnetic field is the derivative of the potential
         // function defined by the model. See NOAA Technical Report: The US/UK
-        // World Magnetic Model for 2005-2010 for the derivation.
+        // World Magnetic Model for 2010-2015 for the derivation.
         float gcX = 0.0f;  // Geocentric northwards component.
         float gcY = 0.0f;  // Geocentric eastwards component.
         float gcZ = 0.0f;  // Geocentric downwards component.
@@ -406,4 +405,4 @@
         }
         return schmidtQuasiNorm;
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index f2ea539..eca4569 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1598,6 +1598,8 @@
                     end = query.length();
                 }
                 return decode(query.substring(equalsIndex + 1, end));
+            } else {
+                encodedKeySearchIndex = equalsIndex + 1;
             }
         }
         return null;
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index 1b6568e..6dbf325 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -82,6 +82,9 @@
     /* Used to synchronize waitUntilComplete() requests */
     private final Object mClientResource = new Object();
 
+    /** True if loading should be paused **/
+    private boolean mLoadingPaused = false;
+
     /**
      * Processor used to set content-length and transfer-encoding
      * headers.
@@ -133,6 +136,18 @@
     }
 
     /**
+     * @param pause True if the load should be paused.
+     */
+    synchronized void setLoadingPaused(boolean pause) {
+        mLoadingPaused = pause;
+
+        // Wake up the paused thread if we're unpausing the load.
+        if (!mLoadingPaused) {
+            notify();
+        }
+    }
+
+    /**
      * @param connection Request served by this connection
      */
     void setConnection(Connection connection) {
@@ -271,7 +286,24 @@
                 int len = 0;
                 int lowWater = buf.length / 2;
                 while (len != -1) {
+                    synchronized(this) {
+                        while (mLoadingPaused) {
+                            // Put this (network loading) thread to sleep if WebCore
+                            // has asked us to. This can happen with plugins for
+                            // example, if we are streaming data but the plugin has
+                            // filled its internal buffers.
+                            try {
+                                wait();
+                            } catch (InterruptedException e) {
+                                HttpLog.e("Interrupted exception whilst "
+                                    + "network thread paused at WebCore's request."
+                                    + " " + e.getMessage());
+                            }
+                        }
+                    }
+
                     len = nis.read(buf, count, buf.length - count);
+
                     if (len != -1) {
                         count += len;
                     }
@@ -316,10 +348,16 @@
      *
      * Called by RequestHandle from non-network thread
      */
-    void cancel() {
+    synchronized void cancel() {
         if (HttpLog.LOGV) {
             HttpLog.v("Request.cancel(): " + getUri());
         }
+
+        // Ensure that the network thread is not blocked by a hanging request from WebCore to
+        // pause the load.
+        mLoadingPaused = false;
+        notify();
+
         mCancelled = true;
         if (mConnection != null) {
             mConnection.cancel();
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 77cd544..1a3a289 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -101,6 +101,16 @@
     }
 
     /**
+     * Pauses the loading of this request. For example, called from the WebCore thread
+     * when the plugin can take no more data.
+     */
+    public void pauseRequest(boolean pause) {
+        if (mRequest != null) {
+            mRequest.setLoadingPaused(pause);
+        }
+    }
+
+    /**
      * Handles SSL error(s) on the way down from the user (the user
      * has already provided their feedback).
      */
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index e4eaf45b..f4ca8bc 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -361,6 +361,9 @@
      */
     public WakeLock newWakeLock(int flags, String tag)
     {
+        if (tag == null) {
+            throw new NullPointerException("tag is null in PowerManager.newWakeLock");
+        }
         return new WakeLock(flags, tag);
     }
 
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 75455ab..4862f80 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -84,7 +84,7 @@
     int[] getStorageUsers(String path);
 
     /**
-     * Gets the state of an volume via it's mountpoint.
+     * Gets the state of a volume via its mountpoint.
      */
     String getVolumeState(String mountPoint);
 
@@ -146,4 +146,10 @@
      * Invokes call back once the shutdown is complete.
      */
     void shutdown(IMountShutdownObserver observer);
+
+    /**
+     * Call into MountService by PackageManager to notify that its done
+     * processing the media status update request.
+     */
+    void finishMediaUpdate();
 }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 53c238c..c44854a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -506,6 +506,17 @@
         updateWindow(false);
     }
 
+    /**
+     * Check to see if the surface has fixed size dimensions or if the surface's
+     * dimensions are dimensions are dependent on its current layout.
+     *
+     * @return true if the surface has dimensions that are fixed in size
+     * @hide
+     */
+    public boolean isFixedSize() {
+        return (mRequestedWidth != -1 || mRequestedHeight != -1);
+    }
+
     private static class MyWindow extends BaseIWindow {
         private final WeakReference<SurfaceView> mSurfaceView;
 
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 2b5489c..d2563a8 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1040,7 +1040,7 @@
             clientStream.writeInt(outRect.width());
             clientStream.writeInt(outRect.height());
     
-            captureViewLayer(root, clientStream);
+            captureViewLayer(root, clientStream, true);
             
             clientStream.write(2);
         } finally {
@@ -1048,9 +1048,11 @@
         }
     }
 
-    private static void captureViewLayer(View view, DataOutputStream clientStream)
+    private static void captureViewLayer(View view, DataOutputStream clientStream, boolean visible)
             throws IOException {
 
+        final boolean localVisible = view.getVisibility() == View.VISIBLE && visible;
+
         if ((view.mPrivateFlags & View.SKIP_DRAW) != View.SKIP_DRAW) {
             final int id = view.getId();
             String name = view.getClass().getSimpleName();
@@ -1060,7 +1062,7 @@
     
             clientStream.write(1);
             clientStream.writeUTF(name);
-            clientStream.writeByte(view.getVisibility() == View.VISIBLE ? 1 : 0);
+            clientStream.writeByte(localVisible ? 1 : 0);
     
             int[] position = new int[2];
             // XXX: Should happen on the UI thread
@@ -1086,7 +1088,7 @@
             int count = group.getChildCount();
 
             for (int i = 0; i < count; i++) {
-                captureViewLayer(group.getChildAt(i), clientStream);
+                captureViewLayer(group.getChildAt(i), clientStream, localVisible);
             }
         }
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 597d583..006aff8 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1274,13 +1274,27 @@
 
     @Override
     Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
-        int oldCount = mChildrenCount;
+        int count = mChildrenCount;
+        int[] visibilities = null;
+
         if (skipChildren) {
-            mChildrenCount = 0;
+            visibilities = new int[count];
+            for (int i = 0; i < count; i++) {
+                View child = getChildAt(i);
+                visibilities[i] = child.getVisibility();
+                if (visibilities[i] == View.VISIBLE) {
+                    child.setVisibility(INVISIBLE);
+                }
+            }
         }
 
         Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
-        mChildrenCount = oldCount;
+
+        if (skipChildren) {
+            for (int i = 0; i < count; i++) {
+                getChildAt(i).setVisibility(visibilities[i]);
+            }        
+        }
 
         return b;
     }
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index dae9187..344b390 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -527,20 +527,12 @@
      */
     private int getFileSize(String uri) {
         int size = 0;
-        Cursor cursor = mContext.getContentResolver().query(Uri.parse(uri),
-                new String[] { OpenableColumns.SIZE },
-                null,
-                null,
-                null);
-        if (cursor != null) {
-            try {
-                if (cursor.moveToNext()) {
-                    size = cursor.getInt(0);
-                }
-            } finally {
-                cursor.close();
-            }
-        }
+        try {
+            InputStream stream = mContext.getContentResolver()
+                            .openInputStream(Uri.parse(uri));
+            size = stream.available();
+            stream.close();
+        } catch (Exception e) {}
         return size;
     }
 
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index dc7723f..2c24757 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -1198,6 +1198,16 @@
     }
 
     /**
+     * Pause the load. For example, if a plugin is unable to accept more data,
+     * we pause reading from the request. Called directly from the WebCore thread.
+     */
+    void pauseLoad(boolean pause) {
+        if (mRequestHandle != null) {
+            mRequestHandle.pauseRequest(pause);
+        }
+    }
+
+    /**
      * Cancel a request.
      * FIXME: This will only work if the request has yet to be handled. This
      * is in no way guarenteed if requests are served in a separate thread.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index cabda85..b5eb5d5 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2618,6 +2618,9 @@
      * @hide
      */
     public void notifyFindDialogDismissed() {
+        if (mWebViewCore == null) {
+            return;
+        }
         clearMatches();
         setFindIsUp(false);
         recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index a870931..a75e6f0 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -389,10 +389,17 @@
             return false;
         }
 
-        Cursor cursor = mDatabase.query(mTableNames[tableId], ID_PROJECTION,
-                null, null, null, null, null);
-        boolean ret = cursor.moveToFirst() == true;
-        cursor.close();
+        Cursor cursor = null;
+        boolean ret = false;
+        try {
+            cursor = mDatabase.query(mTableNames[tableId], ID_PROJECTION,
+                    null, null, null, null, null);
+            ret = cursor.moveToFirst() == true;
+        } catch (IllegalStateException e) {
+            Log.e(LOGTAG, "hasEntries", e);
+        } finally {
+            if (cursor != null) cursor.close();
+        }
         return ret;
     }
 
@@ -420,33 +427,39 @@
             };
             final String selection = "(" + COOKIES_DOMAIN_COL
                     + " GLOB '*' || ?)";
-            Cursor cursor = mDatabase.query(mTableNames[TABLE_COOKIES_ID],
-                    columns, selection, new String[] { domain }, null, null,
-                    null);
-            if (cursor.moveToFirst()) {
-                int domainCol = cursor.getColumnIndex(COOKIES_DOMAIN_COL);
-                int pathCol = cursor.getColumnIndex(COOKIES_PATH_COL);
-                int nameCol = cursor.getColumnIndex(COOKIES_NAME_COL);
-                int valueCol = cursor.getColumnIndex(COOKIES_VALUE_COL);
-                int expiresCol = cursor.getColumnIndex(COOKIES_EXPIRES_COL);
-                int secureCol = cursor.getColumnIndex(COOKIES_SECURE_COL);
-                do {
-                    Cookie cookie = new Cookie();
-                    cookie.domain = cursor.getString(domainCol);
-                    cookie.path = cursor.getString(pathCol);
-                    cookie.name = cursor.getString(nameCol);
-                    cookie.value = cursor.getString(valueCol);
-                    if (cursor.isNull(expiresCol)) {
-                        cookie.expires = -1;
-                    } else {
-                        cookie.expires = cursor.getLong(expiresCol);
-                    }
-                    cookie.secure = cursor.getShort(secureCol) != 0;
-                    cookie.mode = Cookie.MODE_NORMAL;
-                    list.add(cookie);
-                } while (cursor.moveToNext());
+            Cursor cursor = null;
+            try {
+                cursor = mDatabase.query(mTableNames[TABLE_COOKIES_ID],
+                        columns, selection, new String[] { domain }, null, null,
+                        null);
+                if (cursor.moveToFirst()) {
+                    int domainCol = cursor.getColumnIndex(COOKIES_DOMAIN_COL);
+                    int pathCol = cursor.getColumnIndex(COOKIES_PATH_COL);
+                    int nameCol = cursor.getColumnIndex(COOKIES_NAME_COL);
+                    int valueCol = cursor.getColumnIndex(COOKIES_VALUE_COL);
+                    int expiresCol = cursor.getColumnIndex(COOKIES_EXPIRES_COL);
+                    int secureCol = cursor.getColumnIndex(COOKIES_SECURE_COL);
+                    do {
+                        Cookie cookie = new Cookie();
+                        cookie.domain = cursor.getString(domainCol);
+                        cookie.path = cursor.getString(pathCol);
+                        cookie.name = cursor.getString(nameCol);
+                        cookie.value = cursor.getString(valueCol);
+                        if (cursor.isNull(expiresCol)) {
+                            cookie.expires = -1;
+                        } else {
+                            cookie.expires = cursor.getLong(expiresCol);
+                        }
+                        cookie.secure = cursor.getShort(secureCol) != 0;
+                        cookie.mode = Cookie.MODE_NORMAL;
+                        list.add(cookie);
+                    } while (cursor.moveToNext());
+                }
+            } catch (IllegalStateException e) {
+                Log.e(LOGTAG, "getCookiesForDomain", e);
+            } finally {
+                if (cursor != null) cursor.close();
             }
-            cursor.close();
             return list;
         }
     }
@@ -604,12 +617,12 @@
             return null;
         }
 
-        Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, "
-                    + "expiresstring, mimetype, encoding, httpstatus, location, contentlength, "
-                    + "contentdisposition FROM cache WHERE url = ?",
-                new String[] { url });
-
+        Cursor cursor = null;
+        final String query = "SELECT filepath, lastmodify, etag, expires, "
+                + "expiresstring, mimetype, encoding, httpstatus, location, contentlength, "
+                + "contentdisposition FROM cache WHERE url = ?";
         try {
+            cursor = mCacheDatabase.rawQuery(query, new String[] { url });
             if (cursor.moveToFirst()) {
                 CacheResult ret = new CacheResult();
                 ret.localPath = cursor.getString(0);
@@ -625,6 +638,8 @@
                 ret.contentdisposition = cursor.getString(10);
                 return ret;
             }
+        } catch (IllegalStateException e) {
+            Log.e(LOGTAG, "getCache", e);
         } finally {
             if (cursor != null) cursor.close();
         }
@@ -688,78 +703,108 @@
             return false;
         }
 
-        Cursor cursor = mCacheDatabase.query("cache", ID_PROJECTION,
-                null, null, null, null, null);
-        boolean ret = cursor.moveToFirst() == true;
-        cursor.close();
+        Cursor cursor = null;
+        boolean ret = false;
+        try {
+            cursor = mCacheDatabase.query("cache", ID_PROJECTION,
+                    null, null, null, null, null);
+            ret = cursor.moveToFirst() == true;
+        } catch (IllegalStateException e) {
+            Log.e(LOGTAG, "hasCache", e);
+        } finally {
+            if (cursor != null) cursor.close();
+        }
         return ret;
     }
 
     long getCacheTotalSize() {
         long size = 0;
-        Cursor cursor = mCacheDatabase.rawQuery(
-                "SELECT SUM(contentlength) as sum FROM cache", null);
-        if (cursor.moveToFirst()) {
-            size = cursor.getLong(0);
+        Cursor cursor = null;
+        final String query = "SELECT SUM(contentlength) as sum FROM cache";
+        try {
+            cursor = mCacheDatabase.rawQuery(query, null);
+            if (cursor.moveToFirst()) {
+                size = cursor.getLong(0);
+            }
+        } catch (IllegalStateException e) {
+            Log.e(LOGTAG, "getCacheTotalSize", e);
+        } finally {
+            if (cursor != null) cursor.close();
         }
-        cursor.close();
         return size;
     }
 
     List<String> trimCache(long amount) {
         ArrayList<String> pathList = new ArrayList<String>(100);
-        Cursor cursor = mCacheDatabase.rawQuery(
-                "SELECT contentlength, filepath FROM cache ORDER BY expires ASC",
-                null);
-        if (cursor.moveToFirst()) {
-            int batchSize = 100;
-            StringBuilder pathStr = new StringBuilder(20 + 16 * batchSize);
-            pathStr.append("DELETE FROM cache WHERE filepath IN (?");
-            for (int i = 1; i < batchSize; i++) {
-                pathStr.append(", ?");
-            }
-            pathStr.append(")");
-            SQLiteStatement statement = mCacheDatabase.compileStatement(pathStr
-                    .toString());
-            // as bindString() uses 1-based index, initialize index to 1
-            int index = 1;
-            do {
-                long length = cursor.getLong(0);
-                if (length == 0) {
-                    continue;
+        Cursor cursor = null;
+        final String query = "SELECT contentlength, filepath FROM cache ORDER BY expires ASC";
+        try {
+            cursor = mCacheDatabase.rawQuery(query, null);
+            if (cursor.moveToFirst()) {
+                int batchSize = 100;
+                StringBuilder pathStr = new StringBuilder(20 + 16 * batchSize);
+                pathStr.append("DELETE FROM cache WHERE filepath IN (?");
+                for (int i = 1; i < batchSize; i++) {
+                    pathStr.append(", ?");
                 }
-                amount -= length;
-                String filePath = cursor.getString(1);
-                statement.bindString(index, filePath);
-                pathList.add(filePath);
-                if (index++ == batchSize) {
-                    statement.execute();
-                    statement.clearBindings();
-                    index = 1;
+                pathStr.append(")");
+                SQLiteStatement statement = null;
+                try {
+                    statement = mCacheDatabase.compileStatement(
+                            pathStr.toString());
+                    // as bindString() uses 1-based index, initialize index to 1
+                    int index = 1;
+                    do {
+                        long length = cursor.getLong(0);
+                        if (length == 0) {
+                            continue;
+                        }
+                        amount -= length;
+                        String filePath = cursor.getString(1);
+                        statement.bindString(index, filePath);
+                        pathList.add(filePath);
+                        if (index++ == batchSize) {
+                            statement.execute();
+                            statement.clearBindings();
+                            index = 1;
+                        }
+                    } while (cursor.moveToNext() && amount > 0);
+                    if (index > 1) {
+                        // there may be old bindings from the previous statement
+                        // if index is less than batchSize, which is Ok.
+                        statement.execute();
+                    }
+                } catch (IllegalStateException e) {
+                    Log.e(LOGTAG, "trimCache SQLiteStatement", e);
+                } finally {
+                    if (statement != null) statement.close();
                 }
-            } while (cursor.moveToNext() && amount > 0);
-            if (index > 1) {
-                // there may be old bindings from the previous statement if
-                // index is less than batchSize, which is Ok.
-                statement.execute();
             }
-            statement.close();
+        } catch (IllegalStateException e) {
+            Log.e(LOGTAG, "trimCache Cursor", e);
+        } finally {
+            if (cursor != null) cursor.close();
         }
-        cursor.close();
         return pathList;
     }
 
     List<String> getAllCacheFileNames() {
         ArrayList<String> pathList = null;
-        Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath FROM cache",
-                null);
-        if (cursor != null && cursor.moveToFirst()) {
-            pathList = new ArrayList<String>(cursor.getCount());
-            do {
-                pathList.add(cursor.getString(0));
-            } while (cursor.moveToNext());
+        Cursor cursor = null;
+        try {
+            cursor = mCacheDatabase.rawQuery("SELECT filepath FROM cache",
+                    null);
+            if (cursor != null && cursor.moveToFirst()) {
+                pathList = new ArrayList<String>(cursor.getCount());
+                do {
+                    pathList.add(cursor.getString(0));
+                } while (cursor.moveToNext());
+            }
+        } catch (IllegalStateException e) {
+            Log.e(LOGTAG, "getAllCacheFileNames", e);
+        } finally {
+            if (cursor != null) cursor.close();
         }
-        cursor.close();
         return pathList;
     }
 
@@ -809,17 +854,23 @@
         final String selection = "(" + PASSWORD_HOST_COL + " == ?)";
         synchronized (mPasswordLock) {
             String[] ret = null;
-            Cursor cursor = mDatabase.query(mTableNames[TABLE_PASSWORD_ID],
-                    columns, selection, new String[] { schemePlusHost }, null,
-                    null, null);
-            if (cursor.moveToFirst()) {
-                ret = new String[2];
-                ret[0] = cursor.getString(
-                        cursor.getColumnIndex(PASSWORD_USERNAME_COL));
-                ret[1] = cursor.getString(
-                        cursor.getColumnIndex(PASSWORD_PASSWORD_COL));
+            Cursor cursor = null;
+            try {
+                cursor = mDatabase.query(mTableNames[TABLE_PASSWORD_ID],
+                        columns, selection, new String[] { schemePlusHost }, null,
+                        null, null);
+                if (cursor.moveToFirst()) {
+                    ret = new String[2];
+                    ret[0] = cursor.getString(
+                            cursor.getColumnIndex(PASSWORD_USERNAME_COL));
+                    ret[1] = cursor.getString(
+                            cursor.getColumnIndex(PASSWORD_PASSWORD_COL));
+                }
+            } catch (IllegalStateException e) {
+                Log.e(LOGTAG, "getUsernamePassword", e);
+            } finally {
+                if (cursor != null) cursor.close();
             }
-            cursor.close();
             return ret;
         }
     }
@@ -900,17 +951,23 @@
                 + HTTPAUTH_REALM_COL + " == ?)";
         synchronized (mHttpAuthLock) {
             String[] ret = null;
-            Cursor cursor = mDatabase.query(mTableNames[TABLE_HTTPAUTH_ID],
-                    columns, selection, new String[] { host, realm }, null,
-                    null, null);
-            if (cursor.moveToFirst()) {
-                ret = new String[2];
-                ret[0] = cursor.getString(
-                        cursor.getColumnIndex(HTTPAUTH_USERNAME_COL));
-                ret[1] = cursor.getString(
-                        cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL));
+            Cursor cursor = null;
+            try {
+                cursor = mDatabase.query(mTableNames[TABLE_HTTPAUTH_ID],
+                        columns, selection, new String[] { host, realm }, null,
+                        null, null);
+                if (cursor.moveToFirst()) {
+                    ret = new String[2];
+                    ret[0] = cursor.getString(
+                            cursor.getColumnIndex(HTTPAUTH_USERNAME_COL));
+                    ret[1] = cursor.getString(
+                            cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL));
+                }
+            } catch (IllegalStateException e) {
+                Log.e(LOGTAG, "getHttpAuthUsernamePassword", e);
+            } finally {
+                if (cursor != null) cursor.close();
             }
-            cursor.close();
             return ret;
         }
     }
@@ -958,18 +1015,24 @@
         final String selection = "(" + FORMURL_URL_COL + " == ?)";
         synchronized (mFormLock) {
             long urlid = -1;
-            Cursor cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
-                    ID_PROJECTION, selection, new String[] { url }, null, null,
-                    null);
-            if (cursor.moveToFirst()) {
-                urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
-            } else {
-                ContentValues c = new ContentValues();
-                c.put(FORMURL_URL_COL, url);
-                urlid = mDatabase.insert(
-                        mTableNames[TABLE_FORMURL_ID], null, c);
+            Cursor cursor = null;
+            try {
+                cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
+                        ID_PROJECTION, selection, new String[] { url }, null, null,
+                        null);
+                if (cursor.moveToFirst()) {
+                    urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
+                } else {
+                    ContentValues c = new ContentValues();
+                    c.put(FORMURL_URL_COL, url);
+                    urlid = mDatabase.insert(
+                            mTableNames[TABLE_FORMURL_ID], null, c);
+                }
+            } catch (IllegalStateException e) {
+                Log.e(LOGTAG, "setFormData", e);
+            } finally {
+                if (cursor != null) cursor.close();
             }
-            cursor.close();
             if (urlid >= 0) {
                 Set<Entry<String, String>> set = formdata.entrySet();
                 Iterator<Entry<String, String>> iter = set.iterator();
@@ -1002,27 +1065,39 @@
         final String dataSelection = "(" + FORMDATA_URLID_COL + " == ?) AND ("
                 + FORMDATA_NAME_COL + " == ?)";
         synchronized (mFormLock) {
-            Cursor cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
-                    ID_PROJECTION, urlSelection, new String[] { url }, null,
-                    null, null);
-            if (cursor.moveToFirst()) {
-                long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
-                Cursor dataCursor = mDatabase.query(
-                        mTableNames[TABLE_FORMDATA_ID],
-                        new String[] { ID_COL, FORMDATA_VALUE_COL },
-                        dataSelection,
-                        new String[] { Long.toString(urlid), name }, null,
+            Cursor cursor = null;
+            try {
+                cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
+                        ID_PROJECTION, urlSelection, new String[] { url }, null,
                         null, null);
-                if (dataCursor.moveToFirst()) {
-                    int valueCol =
-                            dataCursor.getColumnIndex(FORMDATA_VALUE_COL);
-                    do {
-                        values.add(dataCursor.getString(valueCol));
-                    } while (dataCursor.moveToNext());
+                if (cursor.moveToFirst()) {
+                    long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
+                    Cursor dataCursor = null;
+                    try {
+                        dataCursor = mDatabase.query(
+                                mTableNames[TABLE_FORMDATA_ID],
+                                new String[] { ID_COL, FORMDATA_VALUE_COL },
+                                dataSelection,
+                                new String[] { Long.toString(urlid), name },
+                                null, null, null);
+                        if (dataCursor.moveToFirst()) {
+                            int valueCol = dataCursor.getColumnIndex(
+                                    FORMDATA_VALUE_COL);
+                            do {
+                                values.add(dataCursor.getString(valueCol));
+                            } while (dataCursor.moveToNext());
+                        }
+                    } catch (IllegalStateException e) {
+                        Log.e(LOGTAG, "getFormData dataCursor", e);
+                    } finally {
+                        if (dataCursor != null) dataCursor.close();
+                    }
                 }
-                dataCursor.close();
+            } catch (IllegalStateException e) {
+                Log.e(LOGTAG, "getFormData cursor", e);
+            } finally {
+                if (cursor != null) cursor.close();
             }
-            cursor.close();
             return values;
         }
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 86011d7..a30059c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1835,9 +1835,11 @@
                     mSelectedPosition < mAdapter.getCount()) {
 
                 final View view = getChildAt(mSelectedPosition - mFirstPosition);
-                performItemClick(view, mSelectedPosition, mSelectedRowId);
+                if (view != null) {
+                    performItemClick(view, mSelectedPosition, mSelectedRowId);
+                    view.setPressed(false);
+                }
                 setPressed(false);
-                if (view != null) view.setPressed(false);
                 return true;
             }
             break;
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 3328c13..52a560c 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -216,23 +216,23 @@
     }
 
     /**
-     * Sets the drawable to use as the left part of the strip below the
+     * Sets the drawable to use as the right part of the strip below the
      * tab indicators.
-     * @param drawable the left strip drawable
+     * @param drawable the right strip drawable
      */
     public void setRightStripDrawable(Drawable drawable) {
-        mBottomLeftStrip = drawable;
+        mBottomRightStrip = drawable;
         requestLayout();
         invalidate();    }
 
     /**
-     * Sets the drawable to use as the left part of the strip below the
+     * Sets the drawable to use as the right part of the strip below the
      * tab indicators.
      * @param resId the resource identifier of the drawable to use as the
-     * left strip drawable
+     * right strip drawable
      */
     public void setRightStripDrawable(int resId) {
-        mBottomLeftStrip = mContext.getResources().getDrawable(resId);
+        mBottomRightStrip = mContext.getResources().getDrawable(resId);
         requestLayout();
         invalidate();
     }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 9b7f487..37cd412 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -89,7 +89,7 @@
     public static final int MODE_UNSPECIFIED = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     public static final int MODE_PATTERN = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
     public static final int MODE_PIN = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-    public static final int MODE_PASSWORD = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+    public static final int MODE_PASSWORD = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
 
     /**
      * The minimum number of dots the user must include in a wrong pattern
@@ -144,12 +144,11 @@
     /**
      * Gets the device policy password mode. If the mode is non-specific, returns
      * MODE_PATTERN which allows the user to choose anything.
-     *
-     * @return
      */
     public int getRequestedPasswordMode() {
         int policyMode = getDevicePolicyManager().getPasswordQuality(null);
         switch (policyMode) {
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
                 return MODE_PASSWORD;
             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
@@ -270,9 +269,41 @@
     }
 
     /**
+     * Used by device policy manager to validate the current password
+     * information it has.
+     */
+    public int getActivePasswordQuality() {
+        switch (getPasswordMode()) {
+            case MODE_UNSPECIFIED:
+                return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+            case MODE_PATTERN:
+                if (isLockPatternEnabled()) {
+                    return DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+                } else {
+                    return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                }
+            case MODE_PIN:
+                if (isLockPasswordEnabled()) {
+                    return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+                } else {
+                    return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                }
+            case MODE_PASSWORD:
+                if (isLockPasswordEnabled()) {
+                    return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+                } else {
+                    return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                }
+        }
+        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+    }
+    
+    /**
      * Clear any lock pattern or password.
      */
     public void clearLock() {
+        getDevicePolicyManager().setActivePasswordState(
+                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
         saveLockPassword(null, LockPatternUtils.MODE_PATTERN);
         setLockPatternEnabled(false);
         saveLockPattern(null);
@@ -316,15 +347,9 @@
     }
 
     /**
-     * Compare the given password and mode, ensuring that the password meets
-     * the mode and returning the minimum mode needed for the given password.
-     * @param password The password to be used.
-     * @param reqMode The desired password mode.
-     * @return Returns {@link #MODE_UNSPECIFIED} if the password is not
-     * good enough for the given mode.  Otherwise, returns either the original
-     * reqMode or something better if that is needed for the given password.
+     * Compute the password quality from the given password string.
      */
-    static public int adjustPasswordMode(String password, int reqMode) {
+    static public int computePasswordQuality(String password) {
         boolean hasDigit = false;
         boolean hasNonDigit = false;
         final int len = password.length();
@@ -336,39 +361,16 @@
             }
         }
 
-        // First check if it is sufficient.
-        switch (reqMode) {
-            case MODE_PASSWORD: {
-                if (!hasDigit || !hasNonDigit) {
-                    return MODE_UNSPECIFIED;
-                }
-            } break;
-
-            case MODE_PIN:
-            case MODE_PATTERN: {
-                // Whatever we have is acceptable; we may need to promote the
-                // mode later.
-            } break;
-
-            default:
-                // If it isn't a mode we specifically know, then fail fast.
-                Log.w(TAG, "adjustPasswordMode: unknown mode " + reqMode);
-                return MODE_UNSPECIFIED;
+        if (hasNonDigit && hasDigit) {
+            return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
         }
-
-        // Do we need to promote?
         if (hasNonDigit) {
-            if (reqMode < MODE_PASSWORD) {
-                reqMode = MODE_PASSWORD;
-            }
+            return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
         }
         if (hasDigit) {
-            if (reqMode < MODE_PIN) {
-                reqMode = MODE_PIN;
-            }
+            return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
         }
-
-        return reqMode;
+        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     }
 
     /**
@@ -392,12 +394,15 @@
             raf.close();
             DevicePolicyManager dpm = getDevicePolicyManager();
             if (password != null) {
-                int finalMode = adjustPasswordMode(password, mode);
-                if (mode < finalMode) {
-                    mode = finalMode;
-                }
                 setLong(PASSWORD_TYPE_KEY, mode);
-                dpm.setActivePasswordState(mode, password.length());
+                int quality = computePasswordQuality(password);
+                if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                    dpm.setActivePasswordState(quality, password.length());
+                } else {
+                    // The password is not anything.
+                    dpm.setActivePasswordState(
+                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
+                }
             } else {
                 dpm.setActivePasswordState(
                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index 2a1f23a..d4ac24a 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -424,7 +424,8 @@
                     // faster.
                     if ("text/plain".equals(type) || "application/smil".equals(type)) {
                         String text = c.getString(PART_COLUMN_TEXT);
-                        byte [] blob = new EncodedStringValue(text).getTextString();
+                        byte [] blob = new EncodedStringValue(text != null ? text : "")
+                            .getTextString();
                         baos.write(blob, 0, blob.length);
                     } else {
 
@@ -858,7 +859,7 @@
         } else {
             values.put(Mms.SUBJECT, "");
         }
-        
+
         long messageSize = sendReq.getMessageSize();
         if (messageSize > 0) {
             values.put(Mms.MESSAGE_SIZE, messageSize);
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 5432efb..0e7fd66 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -564,7 +564,10 @@
                                 NULL, NULL, NULL, NULL, NULL);
                         tearDownEventLoop(nat);
                         nat->vm->DetachCurrentThread();
-                        shutdown(nat->controlFdR,SHUT_RDWR);
+
+                        int fd = nat->controlFdR;
+                        nat->controlFdR = 0;
+                        close(fd);
                         return NULL;
                     }
                     case EVENT_LOOP_ADD:
@@ -653,9 +656,12 @@
 
 done:
     if (JNI_FALSE == result) {
-        if (nat->controlFdW || nat->controlFdR) {
-            shutdown(nat->controlFdW, SHUT_RDWR);
+        if (nat->controlFdW) {
+            close(nat->controlFdW);
             nat->controlFdW = 0;
+        }
+        if (nat->controlFdR) {
+            close(nat->controlFdR);
             nat->controlFdR = 0;
         }
         if (nat->me) env->DeleteGlobalRef(nat->me);
@@ -692,9 +698,10 @@
         nat->watchData = NULL;
         nat->pollDataSize = 0;
         nat->pollMemberCount = 0;
-        shutdown(nat->controlFdW, SHUT_RDWR);
+
+        int fd = nat->controlFdW;
         nat->controlFdW = 0;
-        nat->controlFdR = 0;
+        close(fd);
     }
     pthread_mutex_unlock(&(nat->thread_mutex));
 #endif // HAVE_BLUETOOTH
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4e2caa0..a3c73d8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -732,7 +732,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_ACCESS"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_access"
         android:description="@string/permdesc_asec_access" />
 
@@ -740,7 +740,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_CREATE"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_create"
         android:description="@string/permdesc_asec_create" />
 
@@ -748,7 +748,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_DESTROY"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_destroy"
         android:description="@string/permdesc_asec_destroy" />
 
@@ -756,7 +756,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_mount_unmount"
         android:description="@string/permdesc_asec_mount_unmount" />
 
@@ -764,7 +764,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_RENAME"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_rename"
         android:description="@string/permdesc_asec_rename" />
 
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index ad71fcb..095ee13 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -574,5 +574,13 @@
             .appendQueryParameter("key", "y z")
             .build();
         assertEquals("y z", uri.getQueryParameter("key"));
+
+        // key is a substring of parameters, but not present
+        uri = Uri.parse("http://test/").buildUpon()
+            .appendQueryParameter("akeyb", "a b")
+            .appendQueryParameter("keya", "c d")
+            .appendQueryParameter("bkey", "e f")
+            .build();
+        assertNull(uri.getQueryParameter("key"));
     }
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 68b351b..b56e638 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1472,8 +1472,6 @@
     //====================================================================
     // Remote Control
     /**
-     * @hide
-     * TODO unhide for SDK
      * TODO document for SDK
      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
      *      that will receive the media button intent. This broadcast receiver must be declared
@@ -1490,21 +1488,6 @@
     }
 
     /**
-     * @hide
-     * TODO unhide for SDK
-     * TODO document for SDK
-     * @param eventReceiverClass class of a {@link android.content.BroadcastReceiver} that will
-     *     receive the media button intent. This broadcast receiver must be declared in the
-     *     application manifest.
-     */
-    public void registerMediaButtonEventReceiver(Class<?> eventReceiverClass) {
-        registerMediaButtonEventReceiver(new ComponentName(
-                eventReceiverClass.getPackage().getName(), eventReceiverClass.getName()));
-    }
-
-    /**
-     * @hide
-     * TODO unhide for SDK
      * TODO document for SDK
      */
     public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
@@ -1517,16 +1500,6 @@
     }
 
     /**
-     * @hide
-     * TODO unhide for SDK
-     * TODO document for SDK
-     */
-    public void unregisterMediaButtonEventReceiver(Class<?> eventReceiverClass) {
-        unregisterMediaButtonEventReceiver(new ComponentName(
-                eventReceiverClass.getPackage().getName(), eventReceiverClass.getName()));
-    }
-
-    /**
      *  @hide
      *  Reload audio settings. This method is called by Settings backup
      *  agent when audio settings are restored and causes the AudioService
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ae0eccb..74e6157 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -208,6 +208,9 @@
     /** @see System#MODE_RINGER_STREAMS_AFFECTED */
     private int mRingerModeAffectedStreams;
 
+    // Streams currently muted by ringer mode
+    private int mRingerModeMutedStreams;
+
     /** @see System#MUTE_STREAMS_AFFECTED */
     private int mMuteAffectedStreams;
 
@@ -404,7 +407,7 @@
 
 
         VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
-        final int oldIndex = streamState.mIndex;
+        final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex;
         boolean adjustVolume = true;
 
         // If either the client forces allowing ringer modes for this adjustment,
@@ -416,30 +419,43 @@
             adjustVolume = checkForRingerModeChange(oldIndex, direction);
         }
 
-        if (adjustVolume && streamState.adjustIndex(direction)) {
-            // Post message to set system volume (it in turn will post a message
-            // to persist). Do not change volume if stream is muted.
-            if (streamState.muteCount() == 0) {
+        // If stream is muted, adjust last audible index only
+        int index;
+        if (streamState.muteCount() != 0) {
+            if (adjustVolume) {
+                streamState.adjustLastAudibleIndex(direction);
+                // Post a persist volume msg
+                sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+                        SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+            }
+            index = streamState.mLastAudibleIndex;
+        } else {
+            if (adjustVolume && streamState.adjustIndex(direction)) {
+                // Post message to set system volume (it in turn will post a message
+                // to persist). Do not change volume if stream is muted.
                 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0,
                         streamState, 0);
             }
+            index = streamState.mIndex;
         }
-
         // UI
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
-        sendVolumeUpdate(streamType, oldIndex, streamState.mIndex);
+        sendVolumeUpdate(streamType, oldIndex, index);
     }
 
     /** @see AudioManager#setStreamVolume(int, int, int) */
     public void setStreamVolume(int streamType, int index, int flags) {
         ensureValidStreamType(streamType);
+        VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
 
-        final int oldIndex = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
+        final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex;
 
         index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
         setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true);
 
+        index = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex;
+
         // UI, etc.
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
@@ -470,22 +486,30 @@
      */
     private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) {
         VolumeStreamState streamState = mStreamStates[streamType];
-        if (streamState.setIndex(index, lastAudible) || force) {
-            // Post message to set system volume (it in turn will post a message
-            // to persist).
-            // If stream is muted or we are in silent mode and stream is affected by ringer mode
-            // and the new volume is not 0, just persist the new volume but do not change
-            // current value
-            if (streamState.muteCount() == 0 &&
-                (mRingerMode == AudioManager.RINGER_MODE_NORMAL ||
-                !isStreamAffectedByRingerMode(streamType) ||
-                index == 0)) {
-                sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
-                        streamState, 0);
-            } else {
-                // Post a persist volume msg
-                sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
-                        SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+
+        // If stream is muted, set last audible index only
+        if (streamState.muteCount() != 0) {
+            streamState.setLastAudibleIndex(index);
+            // Post a persist volume msg
+            sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+                    SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+        } else {
+            if (streamState.setIndex(index, lastAudible) || force) {
+                // Post message to set system volume (it in turn will post a message
+                // to persist).
+                // If we are in silent mode and stream is affected by ringer mode
+                // and the new volume is not 0, just persist the new volume but do not change
+                // current value
+                if (mRingerMode == AudioManager.RINGER_MODE_NORMAL ||
+                    !isStreamAffectedByRingerMode(streamType) ||
+                    index == 0) {
+                    sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
+                            streamState, 0);
+                } else {
+                    // Post a persist volume msg
+                    sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+                            SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+                }
             }
         }
     }
@@ -537,27 +561,24 @@
     private void setRingerModeInt(int ringerMode, boolean persist) {
         mRingerMode = ringerMode;
 
-        // Adjust volumes via posting message
+        // Mute stream if not previously muted by ringer mode and ringer mode
+        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
+        // Unmute stream if previously muted by ringer mode and ringer mode
+        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
         int numStreamTypes = AudioSystem.getNumStreamTypes();
-        if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
-            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                if (!isStreamAffectedByRingerMode(streamType)) continue;
-                // Bring back last audible volume
-                setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
-                                   true, false);
-            }
-        } else {
-            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                if (isStreamAffectedByRingerMode(streamType)) {
-                    // Either silent or vibrate, either way volume is 0
-                    setStreamVolumeInt(streamType, 0, false, false);
-                } else {
-                    // restore stream volume in the case the stream changed from affected
-                    // to non affected by ringer mode. Does not arm to do it for streams that
-                    // are not affected as well.
-                    setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
-                            true, false);
+        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+            if (isStreamMutedByRingerMode(streamType)) {
+                if (!isStreamAffectedByRingerMode(streamType) ||
+                    mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
+                    mStreamStates[streamType].mute(null, false);
+                    mRingerModeMutedStreams &= ~(1 << streamType);
                 }
+            } else {
+                if (isStreamAffectedByRingerMode(streamType) &&
+                    mRingerMode != AudioManager.RINGER_MODE_NORMAL) {
+                   mStreamStates[streamType].mute(null, true);
+                   mRingerModeMutedStreams |= (1 << streamType);
+               }
             }
         }
 
@@ -728,7 +749,7 @@
             }
             int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
             int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
-            setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, true);
+            setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false);
         }
     }
 
@@ -862,7 +883,7 @@
             }
             streamState.mLastAudibleIndex = streamState.getValidIndex(index);
 
-            // unmute stream that whas muted but is not affect by mute anymore
+            // unmute stream that was muted but is not affect by mute anymore
             if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
                 int size = streamState.mDeathHandlers.size();
                 for (int i = 0; i < size; i++) {
@@ -1127,6 +1148,10 @@
         return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
     }
 
+    private boolean isStreamMutedByRingerMode(int streamType) {
+        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
+    }
+
     public boolean isStreamAffectedByMute(int streamType) {
         return (mMuteAffectedStreams & (1 << streamType)) != 0;
     }
@@ -1293,6 +1318,14 @@
             }
         }
 
+        public void setLastAudibleIndex(int index) {
+            mLastAudibleIndex = getValidIndex(index);
+        }
+
+        public void adjustLastAudibleIndex(int deltaIndex) {
+            setLastAudibleIndex(mLastAudibleIndex + deltaIndex * 10);
+        }
+
         public int getMaxIndex() {
             return mIndexMax;
         }
@@ -1330,7 +1363,10 @@
                         if (mMuteCount == 0) {
                             // Register for client death notification
                             try {
-                                mICallback.linkToDeath(this, 0);
+                                // mICallback can be 0 if muted by AudioService
+                                if (mICallback != null) {
+                                    mICallback.linkToDeath(this, 0);
+                                }
                                 mDeathHandlers.add(this);
                                 // If the stream is not yet muted by any client, set lvel to 0
                                 if (muteCount() == 0) {
@@ -1356,9 +1392,12 @@
                             if (mMuteCount == 0) {
                                 // Unregistr from client death notification
                                 mDeathHandlers.remove(this);
-                                mICallback.unlinkToDeath(this, 0);
+                                // mICallback can be 0 if muted by AudioService
+                                if (mICallback != null) {
+                                    mICallback.unlinkToDeath(this, 0);
+                                }
                                 if (muteCount() == 0) {
-                                    // If the stream is not mut any more, restore it's volume if
+                                    // If the stream is not muted any more, restore it's volume if
                                     // ringer mode allows it
                                     if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
                                         setIndex(mLastAudibleIndex, false);
@@ -1398,7 +1437,7 @@
                 int size = mDeathHandlers.size();
                 for (int i = 0; i < size; i++) {
                     handler = mDeathHandlers.get(i);
-                    if (cb.equals(handler.mICallback)) {
+                    if (cb == handler.mICallback) {
                         return handler;
                     }
                 }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 1d71577..7fb7db0 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -46,7 +46,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.util.Log;
+import android.util.Slog;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Xml;
@@ -150,7 +150,7 @@
                     maximumFailedPasswordsForWipe = Integer.parseInt(
                             parser.getAttributeValue(null, "value"));
                 } else {
-                    Log.w(TAG, "Unknown admin tag: " + tag);
+                    Slog.w(TAG, "Unknown admin tag: " + tag);
                 }
                 XmlUtils.skipCurrentTag(parser);
             }
@@ -165,8 +165,8 @@
                     pw.print(prefix); pw.print("  "); pw.println(pols.get(i).tag);
                 }
             }
-            pw.print(prefix); pw.print("passwordQuality=");
-                    pw.print(passwordQuality);
+            pw.print(prefix); pw.print("passwordQuality=0x");
+                    pw.print(Integer.toHexString(passwordQuality));
                     pw.print(" minimumPasswordLength=");
                     pw.println(minimumPasswordLength);
             pw.print(prefix); pw.print("maximumTimeToUnlock=");
@@ -185,7 +185,7 @@
                     int change = isPackageDisappearing(aa.info.getPackageName()); 
                     if (change == PACKAGE_PERMANENT_CHANGE
                             || change == PACKAGE_TEMPORARY_CHANGE) {
-                        Log.w(TAG, "Admin unexpectedly uninstalled: "
+                        Slog.w(TAG, "Admin unexpectedly uninstalled: "
                                 + aa.info.getComponent());
                         removed = true;
                         mAdminList.remove(i);
@@ -194,7 +194,7 @@
                             mContext.getPackageManager().getReceiverInfo(
                                     aa.info.getComponent(), 0);
                         } catch (NameNotFoundException e) {
-                            Log.w(TAG, "Admin package change removed component: "
+                            Slog.w(TAG, "Admin package change removed component: "
                                     + aa.info.getComponent());
                             removed = true;
                             mAdminList.remove(i);
@@ -308,10 +308,10 @@
         try {
             return new DeviceAdminInfo(mContext, infos.get(0));
         } catch (XmlPullParserException e) {
-            Log.w(TAG, "Bad device admin requested: " + adminName, e);
+            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
             return null;
         } catch (IOException e) {
-            Log.w(TAG, "Bad device admin requested: " + adminName, e);
+            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
             return null;
         }
     }
@@ -343,8 +343,6 @@
                 }
             }
             
-            out.endTag(null, "policies");
-
             if (mPasswordOwner >= 0) {
                 out.startTag(null, "password-owner");
                 out.attribute(null, "value", Integer.toString(mPasswordOwner));
@@ -357,6 +355,15 @@
                 out.endTag(null, "failed-password-attempts");
             }
             
+            if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
+                out.startTag(null, "active-password");
+                out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
+                out.attribute(null, "length", Integer.toString(mActivePasswordLength));
+                out.endTag(null, "active-password");
+            }
+            
+            out.endTag(null, "policies");
+
             out.endDocument();
             stream.close();
             journal.commit();
@@ -410,7 +417,7 @@
                             mAdminList.add(ap);
                         }
                     } catch (RuntimeException e) {
-                        Log.w(TAG, "Failed loading admin " + name, e);
+                        Slog.w(TAG, "Failed loading admin " + name, e);
                     }
                 } else if ("failed-password-attempts".equals(tag)) {
                     mFailedPasswordAttempts = Integer.parseInt(
@@ -420,21 +427,27 @@
                     mPasswordOwner = Integer.parseInt(
                             parser.getAttributeValue(null, "value"));
                     XmlUtils.skipCurrentTag(parser);
+                } else if ("active-password".equals(tag)) {
+                    mActivePasswordQuality = Integer.parseInt(
+                            parser.getAttributeValue(null, "quality"));
+                    mActivePasswordLength = Integer.parseInt(
+                            parser.getAttributeValue(null, "length"));
+                    XmlUtils.skipCurrentTag(parser);
                 } else {
-                    Log.w(TAG, "Unknown tag: " + tag);
+                    Slog.w(TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
                 }
             }
         } catch (NullPointerException e) {
-            Log.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(TAG, "failed parsing " + file + " " + e);
         } catch (NumberFormatException e) {
-            Log.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(TAG, "failed parsing " + file + " " + e);
         } catch (XmlPullParserException e) {
-            Log.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(TAG, "failed parsing " + file + " " + e);
         } catch (IOException e) {
-            Log.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(TAG, "failed parsing " + file + " " + e);
         } catch (IndexOutOfBoundsException e) {
-            Log.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(TAG, "failed parsing " + file + " " + e);
         }
         try {
             if (stream != null) {
@@ -444,6 +457,20 @@
             // Ignore
         }
 
+        // Validate that what we stored for the password quality matches
+        // sufficiently what is currently set.  Note that this is only
+        // a sanity check in case the two get out of sync; this should
+        // never normally happen.
+        LockPatternUtils utils = new LockPatternUtils(mContext);
+        if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
+            Slog.w(TAG, "Active password quality 0x"
+                    + Integer.toHexString(mActivePasswordQuality)
+                    + " does not match actual quality 0x"
+                    + Integer.toHexString(utils.getActivePasswordQuality()));
+            mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+            mActivePasswordLength = 0;
+        }
+        
         validatePasswordOwnerLocked();
         
         long timeMs = getMaximumTimeToLock(null);
@@ -453,10 +480,23 @@
         try {
             getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
         } catch (RemoteException e) {
-            Log.w(TAG, "Failure talking with power manager", e);
+            Slog.w(TAG, "Failure talking with power manager", e);
         }
     }
 
+    static void validateQualityConstant(int quality) {
+        switch (quality) {
+            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
+            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+                return;
+        }
+        throw new IllegalArgumentException("Invalid quality constant: 0x"
+                + Integer.toHexString(quality));
+    }
+    
     void validatePasswordOwnerLocked() {
         if (mPasswordOwner >= 0) {
             boolean haveOwner = false;
@@ -467,7 +507,7 @@
                 }
             }
             if (!haveOwner) {
-                Log.w(TAG, "Previous password owner " + mPasswordOwner
+                Slog.w(TAG, "Previous password owner " + mPasswordOwner
                         + " no longer active; disabling");
                 mPasswordOwner = -1;
             }
@@ -557,15 +597,17 @@
         }
     }
     
-    public void setPasswordQuality(ComponentName who, int mode) {
+    public void setPasswordQuality(ComponentName who, int quality) {
+        validateQualityConstant(quality);
+        
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
-            if (ap.passwordQuality != mode) {
-                ap.passwordQuality = mode;
+            if (ap.passwordQuality != quality) {
+                ap.passwordQuality = quality;
                 saveSettingsLocked();
             }
         }
@@ -693,23 +735,27 @@
                     DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
             quality = getPasswordQuality(null);
             if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                int adjQuality = LockPatternUtils.adjustPasswordMode(password, quality);
-                if (adjQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                    Log.w(TAG, "resetPassword: password does not meet quality " + quality);
+                int realQuality = LockPatternUtils.computePasswordQuality(password);
+                if (realQuality < quality) {
+                    Slog.w(TAG, "resetPassword: password quality 0x"
+                            + Integer.toHexString(quality)
+                            + " does not meet required quality 0x"
+                            + Integer.toHexString(quality));
                     return false;
                 }
-                quality = adjQuality;
+                quality = realQuality;
             }
             int length = getPasswordMinimumLength(null);
             if (password.length() < length) {
-                Log.w(TAG, "resetPassword: password does not meet length " + length);
+                Slog.w(TAG, "resetPassword: password length " + password.length()
+                        + " does not meet required length " + length);
                 return false;
             }
         }
         
         int callingUid = Binder.getCallingUid();
         if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
-            Log.w(TAG, "resetPassword: already set by another uid and not entered by user");
+            Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
             return false;
         }
         
@@ -719,11 +765,13 @@
         try {
             LockPatternUtils utils = new LockPatternUtils(mContext);
             utils.saveLockPassword(password, quality);
-            int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
-                    != 0 ? callingUid : -1;
-            if (mPasswordOwner != newOwner) {
-                mPasswordOwner = newOwner;
-                saveSettingsLocked();
+            synchronized (this) {
+                int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
+                        != 0 ? callingUid : -1;
+                if (mPasswordOwner != newOwner) {
+                    mPasswordOwner = newOwner;
+                    saveSettingsLocked();
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -754,7 +802,7 @@
                     try {
                         getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
                     } catch (RemoteException e) {
-                        Log.w(TAG, "Failure talking with power manager", e);
+                        Slog.w(TAG, "Failure talking with power manager", e);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -807,7 +855,7 @@
         try {
             RecoverySystem.rebootWipeUserData(mContext);
         } catch (IOException e) {
-            Log.w(TAG, "Failed requesting data wipe", e);
+            Slog.w(TAG, "Failed requesting data wipe", e);
         }
     }
     
@@ -857,6 +905,8 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
         
+        validateQualityConstant(quality);
+        
         synchronized (this) {
             if (mActivePasswordQuality != quality || mActivePasswordLength != length
                     || mFailedPasswordAttempts != 0) {
@@ -864,10 +914,8 @@
                 try {
                     mActivePasswordQuality = quality;
                     mActivePasswordLength = length;
-                    if (mFailedPasswordAttempts != 0) {
-                        mFailedPasswordAttempts = 0;
-                        saveSettingsLocked();
-                    }
+                    mFailedPasswordAttempts = 0;
+                    saveSettingsLocked();
                     sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
                 } finally {
@@ -946,7 +994,8 @@
             }
             
             pw.println(" ");
-            pw.print("  mActivePasswordQuality="); pw.println(mActivePasswordQuality);
+            pw.print("  mActivePasswordQuality=0x");
+                    pw.println(Integer.toHexString(mActivePasswordQuality));
             pw.print("  mActivePasswordLength="); pw.println(mActivePasswordLength);
             pw.print("  mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
             pw.print("  mPasswordOwner="); pw.println(mPasswordOwner);
diff --git a/services/java/com/android/server/EntropyService.java b/services/java/com/android/server/EntropyService.java
index 0a53e9c..81ae26f 100644
--- a/services/java/com/android/server/EntropyService.java
+++ b/services/java/com/android/server/EntropyService.java
@@ -48,14 +48,15 @@
  * instead of periodically.
  */
 public class EntropyService extends Binder {
-    private static final String ENTROPY_FILENAME = getSystemDir() + "/entropy.dat";
     private static final String TAG = "EntropyService";
     private static final int ENTROPY_WHAT = 1;
     private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000;  // 3 hrs
-    private static final String RANDOM_DEV = "/dev/urandom";
     private static final long START_TIME = System.currentTimeMillis();
     private static final long START_NANOTIME = System.nanoTime();
 
+    private final String randomDevice;
+    private final String entropyFile;
+
     /**
      * Handler that periodically updates the entropy on disk.
      */
@@ -72,6 +73,16 @@
     };
 
     public EntropyService() {
+        this(getSystemDir() + "/entropy.dat", "/dev/urandom");
+    }
+
+    /** Test only interface, not for public use */
+    public EntropyService(String entropyFile, String randomDevice) {
+        if (randomDevice == null) { throw new NullPointerException("randomDevice"); }
+        if (entropyFile == null) { throw new NullPointerException("entropyFile"); }
+
+        this.randomDevice = randomDevice;
+        this.entropyFile = entropyFile;
         loadInitialEntropy();
         addDeviceSpecificEntropy();
         writeEntropy();
@@ -85,7 +96,7 @@
 
     private void loadInitialEntropy() {
         try {
-            RandomBlock.fromFile(ENTROPY_FILENAME).toFile(RANDOM_DEV);
+            RandomBlock.fromFile(entropyFile).toFile(randomDevice);
         } catch (IOException e) {
             Slog.w(TAG, "unable to load initial entropy (first boot?)", e);
         }
@@ -93,7 +104,7 @@
 
     private void writeEntropy() {
         try {
-            RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
+            RandomBlock.fromFile(randomDevice).toFile(entropyFile);
         } catch (IOException e) {
             Slog.w(TAG, "unable to write entropy", e);
         }
@@ -116,7 +127,7 @@
     private void addDeviceSpecificEntropy() {
         PrintWriter out = null;
         try {
-            out = new PrintWriter(new FileOutputStream(RANDOM_DEV));
+            out = new PrintWriter(new FileOutputStream(randomDevice));
             out.println("Copyright (C) 2009 The Android Open Source Project");
             out.println("All Your Randomness Are Belong To Us");
             out.println(START_TIME);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d50f591..a4703de 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -135,17 +135,6 @@
     private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
     private static final int MAX_UNMOUNT_RETRIES = 4;
 
-    private IntentFilter mPmFilter = new IntentFilter(
-            Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-    private BroadcastReceiver mPmReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-                mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
-            }
-        }
-    };
-
     class UnmountCallBack {
         String path;
         int retries;
@@ -200,49 +189,35 @@
 
     class MountServiceHandler extends Handler {
         ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
-        boolean mRegistered = false;
+        boolean mUpdatingStatus = false;
 
         MountServiceHandler(Looper l) {
             super(l);
         }
 
-        void registerReceiver() {
-            mRegistered = true;
-            if (DEBUG_UNMOUNT) Log.i(TAG, "Registering receiver");
-            mContext.registerReceiver(mPmReceiver, mPmFilter);
-        }
-
-        void unregisterReceiver() {
-            mRegistered = false;
-            if (DEBUG_UNMOUNT) Log.i(TAG, "Unregistering receiver");
-            mContext.unregisterReceiver(mPmReceiver);
-        }
-
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case H_UNMOUNT_PM_UPDATE: {
                     if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_UPDATE");
                     UnmountCallBack ucb = (UnmountCallBack) msg.obj;
                     mForceUnmounts.add(ucb);
-                    if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mRegistered);
+                    if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mUpdatingStatus);
                     // Register only if needed.
-                    if (!mRegistered) {
-                        registerReceiver();
-                        if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status");
-                        boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
-                        if (!hasExtPkgs) {
-                            // Unregister right away
-                            mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
-                        }
+                    if (!mUpdatingStatus) {
+                        if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status on PackageManager");
+                        mUpdatingStatus = true;
+                        mPms.updateExternalMediaStatus(false, true);
                     }
                     break;
                 }
                 case H_UNMOUNT_PM_DONE: {
                     if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_DONE");
-                    // Unregister now.
-                    if (mRegistered) {
-                        unregisterReceiver();
+                    if (!mUpdatingStatus) {
+                        // Does not correspond to unmount's status update.
+                        return;
                     }
+                    if (DEBUG_UNMOUNT) Log.i(TAG, "Updated status. Processing requests");
+                    mUpdatingStatus = false;
                     int size = mForceUnmounts.size();
                     int sizeArr[] = new int[size];
                     int sizeArrN = 0;
@@ -261,7 +236,7 @@
                                 ActivityManagerService ams = (ActivityManagerService)
                                 ServiceManager.getService("activity");
                                 // Eliminate system process here?
-                                boolean ret = ams.killPidsForMemory(pids);
+                                boolean ret = ams.killPids(pids, "Unmount media");
                                 if (ret) {
                                     // Confirm if file references have been freed.
                                     pids = getStorageUsers(path);
@@ -277,8 +252,8 @@
                                     ucb));
                         } else {
                             if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
-                                Log.i(TAG, "Cannot unmount inspite of " +
-                                        MAX_UNMOUNT_RETRIES + " to unmount media");
+                                Log.i(TAG, "Cannot unmount media inspite of " +
+                                        MAX_UNMOUNT_RETRIES + " retries");
                                 // Send final broadcast indicating failure to unmount.                 
                             } else {
                                 mHandler.sendMessageDelayed(
@@ -337,16 +312,23 @@
                     public void run() {
                         try {
                             String path = Environment.getExternalStorageDirectory().getPath();
-                            if (getVolumeState(
-                                    Environment.getExternalStorageDirectory().getPath()).equals(
-                                            Environment.MEDIA_UNMOUNTED)) {
+                            String state = getVolumeState(path);
+
+                            if (state.equals(Environment.MEDIA_UNMOUNTED)) {
                                 int rc = doMountVolume(path);
                                 if (rc != StorageResultCode.OperationSucceeded) {
                                     Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
                                 }
+                            } else if (state.equals(Environment.MEDIA_SHARED)) {
+                                /*
+                                 * Bootstrap UMS enabled state since vold indicates
+                                 * the volume is shared (runtime restart while ums enabled)
+                                 */
+                                notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared);
                             }
+
                             /*
-                             * If UMS is connected in boot, send the connected event
+                             * If UMS was connected on boot, send the connected event
                              * now that we're up.
                              */
                             if (mSendUmsConnectedOnBoot) {
@@ -405,9 +387,9 @@
         }
         // Update state on PackageManager
         if (Environment.MEDIA_UNMOUNTED.equals(state)) {
-            mPms.updateExternalMediaStatus(false);
+            mPms.updateExternalMediaStatus(false, false);
         } else if (Environment.MEDIA_MOUNTED.equals(state)) {
-            mPms.updateExternalMediaStatus(true);
+            mPms.updateExternalMediaStatus(true, false);
         }
         String oldState = mLegacyState;
         mLegacyState = state;
@@ -750,19 +732,15 @@
         if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
             return VoldResponseCode.OpFailedVolNotMounted;
         }
-
-        // We unmounted the volume. No of the asec containers are available now.
-        synchronized (mAsecMountSet) {
-            mAsecMountSet.clear();
-        }
-        // Notify PackageManager of potential media removal and deal with
-        // return code later on. The caller of this api should be aware or have been
-        // notified that the applications installed on the media will be killed.
         // Redundant probably. But no harm in updating state again.
-        mPms.updateExternalMediaStatus(false);
+        mPms.updateExternalMediaStatus(false, false);
         try {
             mConnector.doCommand(String.format(
                     "volume unmount %s%s", path, (force ? " force" : "")));
+            // We unmounted the volume. None of the asec containers are available now.
+            synchronized (mAsecMountSet) {
+                mAsecMountSet.clear();
+            }
             return StorageResultCode.OperationSucceeded;
         } catch (NativeDaemonConnectorException e) {
             // Don't worry about mismatch in PackageManager since the
@@ -1225,7 +1203,10 @@
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = StorageResultCode.OperationFailedInternalError;
+            int code = e.getCode();
+            if (code != VoldResponseCode.OpFailedStorageBusy) {
+                rc = StorageResultCode.OperationFailedInternalError;
+            }
         }
 
         if (rc == StorageResultCode.OperationSucceeded) {
@@ -1325,5 +1306,9 @@
         Log.e(TAG, "Got an empty response");
         return "";
     }
+
+    public void finishMediaUpdate() {
+        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+    }
 }
 
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 48b3fbb..f9e1963 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -343,6 +343,7 @@
     static final int POST_INSTALL = 9;
     static final int MCS_RECONNECT = 10;
     static final int MCS_GIVE_UP = 11;
+    static final int UPDATED_MEDIA_STATUS = 12;
 
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
@@ -596,6 +597,13 @@
                         Slog.e(TAG, "Bogus post-install token " + msg.arg1);
                     }
                 } break;
+                case UPDATED_MEDIA_STATUS: {
+                    try {
+                        PackageHelper.getMountService().finishMediaUpdate();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "MountService not running?");
+                    }
+                } break;
             }
         }
     }
@@ -3969,7 +3977,7 @@
                             && ps.permissionsFixed) {
                         // If this is an existing, non-system package, then
                         // we can't add any new permissions to it.
-                        if (!allowedSig && !gp.loadedPermissions.contains(perm)) {
+                        if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
                             allowed = false;
                             // Except...  if this is a permission that was added
                             // to the platform (note: need to only do this when
@@ -3981,7 +3989,7 @@
                                 if (npi.name.equals(perm)
                                         && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
                                     allowed = true;
-                                    Log.i(TAG, "Auto-granting WRITE_EXTERNAL_STORAGE to old pkg "
+                                    Log.i(TAG, "Auto-granting " + perm + " to old pkg "
                                             + pkg.packageName);
                                     break;
                                 }
@@ -4029,7 +4037,6 @@
             // permissions we have now selected are fixed until explicitly
             // changed.
             ps.permissionsFixed = true;
-            gp.loadedPermissions = new HashSet<String>(gp.grantedPermissions);
         }
     }
     
@@ -6940,12 +6947,6 @@
                             pw.print("      "); pw.println(s);
                         }
                     }
-                    if (ps.loadedPermissions.size() > 0) {
-                        pw.println("    loadedPermissions:");
-                        for (String s : ps.loadedPermissions) {
-                            pw.print("      "); pw.println(s);
-                        }
-                    }
                 }
             }
             printedSomething = false;
@@ -7014,10 +7015,6 @@
                     for (String s : su.grantedPermissions) {
                         pw.print("      "); pw.println(s);
                     }
-                    pw.println("    loadedPermissions:");
-                    for (String s : su.loadedPermissions) {
-                        pw.print("      "); pw.println(s);
-                    }
                 }
             }
             
@@ -7520,8 +7517,6 @@
         HashSet<String> grantedPermissions = new HashSet<String>();
         int[] gids;
 
-        HashSet<String> loadedPermissions = new HashSet<String>();
-
         GrantedPermissions(int pkgFlags) {
             setFlags(pkgFlags);
         }
@@ -7621,7 +7616,6 @@
         public void copyFrom(PackageSettingBase base) {
             grantedPermissions = base.grantedPermissions;
             gids = base.gids;
-            loadedPermissions = base.loadedPermissions;
 
             timeStamp = base.timeStamp;
             timeStampString = base.timeStampString;
@@ -8055,7 +8049,6 @@
                             p.userId = dis.userId;
                             // Clone permissions
                             p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
-                            p.loadedPermissions = new HashSet<String>(dis.loadedPermissions);
                             // Clone component info
                             p.disabledComponents = new HashSet<String>(dis.disabledComponents);
                             p.enabledComponents = new HashSet<String>(dis.enabledComponents);
@@ -8160,7 +8153,7 @@
                 }
                 for (PackageSetting pkg:sus.packages) {
                     if (pkg.pkg != null &&
-                            !pkg.pkg.packageName.equalsIgnoreCase(deletedPs.pkg.packageName) &&
+                            !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) &&
                             pkg.pkg.requestedPermissions.contains(eachPerm)) {
                         used = true;
                         break;
@@ -8169,7 +8162,6 @@
                 if (!used) {
                     // can safely delete this permission from list
                     sus.grantedPermissions.remove(eachPerm);
-                    sus.loadedPermissions.remove(eachPerm);
                 }
             }
             // Update gids
@@ -9044,7 +9036,7 @@
                         packageSetting.signatures.readXml(parser, mPastSignatures);
                     } else if (tagName.equals("perms")) {
                         readGrantedPermissionsLP(parser,
-                                packageSetting.loadedPermissions);
+                                packageSetting.grantedPermissions);
                         packageSetting.permissionsFixed = true;
                     } else {
                         reportSettingsProblem(Log.WARN,
@@ -9173,7 +9165,7 @@
                     if (tagName.equals("sigs")) {
                         su.signatures.readXml(parser, mPastSignatures);
                     } else if (tagName.equals("perms")) {
-                        readGrantedPermissionsLP(parser, su.loadedPermissions);
+                        readGrantedPermissionsLP(parser, su.grantedPermissions);
                     } else {
                         reportSettingsProblem(Log.WARN,
                                 "Unknown element under <shared-user>: "
@@ -9373,10 +9365,12 @@
    }
 
    /*
-    * Return true if PackageManager does have packages to be updated.
+    * Update media status on PackageManager.
     */
-   public boolean updateExternalMediaStatus(final boolean mediaStatus) {
-       final boolean ret;
+   public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
+       if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+           throw new SecurityException("Media status can only be updated by the system");
+       }
        synchronized (mPackages) {
            Log.i(TAG, "Updating external media status from " +
                    (mMediaMounted ? "mounted" : "unmounted") + " to " +
@@ -9384,32 +9378,29 @@
            if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
                    mediaStatus+", mMediaMounted=" + mMediaMounted);
            if (mediaStatus == mMediaMounted) {
-               return false;
+               if (reportStatus) {
+                   mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
+               }
+               return;
            }
            mMediaMounted = mediaStatus;
-           Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE);
-           ret = appList != null && appList.size() > 0;
-           if (DEBUG_SD_INSTALL) {
-               if (appList != null) {
-                   for (String app : appList) {
-                       Log.i(TAG, "Should enable " + app + " on sdcard");
-                   }
-               }
-           }
-           if (DEBUG_SD_INSTALL)  Log.i(TAG, "updateExternalMediaStatus returning " + ret);
        }
        // Queue up an async operation since the package installation may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
-               updateExternalMediaStatusInner(mediaStatus, ret);
+               try {
+                   updateExternalMediaStatusInner(mediaStatus);
+               } finally {
+                   if (reportStatus) {
+                       mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
+                   }
+               }
            }
        });
-       return ret;
    }
 
-   private void updateExternalMediaStatusInner(boolean mediaStatus,
-           boolean sendUpdateBroadcast) {
+   private void updateExternalMediaStatusInner(boolean mediaStatus) {
        // If we are up here that means there are packages to be
        // enabled or disabled.
        final String list[] = PackageHelper.getSecureContainerList();
@@ -9474,11 +9465,11 @@
        // Process packages with valid entries.
        if (mediaStatus) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
-           loadMediaPackages(processCids, uidArr, sendUpdateBroadcast, removeCids);
+           loadMediaPackages(processCids, uidArr, removeCids);
            startCleaningPackages();
        } else {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
-           unloadMediaPackages(processCids, uidArr, sendUpdateBroadcast);
+           unloadMediaPackages(processCids, uidArr);
        }
    }
 
@@ -9509,8 +9500,7 @@
     * to avoid unnecessary crashes.
     */
    private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
-           int uidArr[], boolean sendUpdateBroadcast,
-           HashSet<String> removeCids) {
+           int uidArr[], HashSet<String> removeCids) {
        ArrayList<String> pkgList = new ArrayList<String>();
        Set<SdInstallArgs> keys = processCids.keySet();
        boolean doGc = false;
@@ -9553,8 +9543,6 @@
                    // Scan the package
                    if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
                        synchronized (mPackages) {
-                           updatePermissionsLP(pkg.packageName, pkg,
-                                   pkg.permissions.size() > 0, false);
                            retCode = PackageManager.INSTALL_SUCCEEDED;
                            pkgList.add(pkg.packageName);
                            // Post process args
@@ -9578,7 +9566,7 @@
            mSettings.writeLP();
        }
        // Send a broadcast to let everyone know we are done processing
-       if (sendUpdateBroadcast) {
+       if (pkgList.size() > 0) {
            sendResourcesChangedBroadcast(true, pkgList, uidArr);
        }
        if (doGc) {
@@ -9594,7 +9582,7 @@
    }
 
    private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
-           int uidArr[], boolean sendUpdateBroadcast) {
+           int uidArr[]) {
        if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
        ArrayList<String> pkgList = new ArrayList<String>();
        ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
@@ -9617,7 +9605,7 @@
            }
        }
        // Send broadcasts
-       if (sendUpdateBroadcast) {
+       if (pkgList.size() > 0) {
            sendResourcesChangedBroadcast(false, pkgList, uidArr);
        }
        // Force gc
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index d72416d..848997b 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -571,6 +571,7 @@
             binder = b;
             tag = t;
             uid = u == MY_UID ? Process.SYSTEM_UID : u;
+            pid = Binder.getCallingPid();
             if (u != MY_UID || (
                     !"KEEP_SCREEN_ON_FLAG".equals(tag)
                     && !"KeyInputQueue".equals(tag))) {
@@ -595,6 +596,7 @@
         final IBinder binder;
         final String tag;
         final int uid;
+        final int pid;
         final int monitorType;
         boolean activated = true;
         int minState;
@@ -998,7 +1000,8 @@
                    activated = " activated";
                 }
                 pw.println("  " + type + " '" + wl.tag + "'" + acquireCausesWakeup
-                        + activated + " (minState=" + wl.minState + ")");
+                        + activated + " (minState=" + wl.minState + ", uid=" + wl.uid
+                        + ", pid=" + wl.pid + ")");
             }
 
             pw.println();
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 93e45fc..fdb67f8 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -10755,7 +10755,7 @@
                         pids[i] = pidCandidates.keyAt(i);
                     }
                     try {
-                        if (mActivityManager.killPidsForMemory(pids)) {
+                        if (mActivityManager.killPids(pids, "Free memory")) {
                             killedApps = true;
                         }
                     } catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2ecebed..7034c88 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8359,11 +8359,11 @@
         }
     }
 
-    public boolean killPidsForMemory(int[] pids) {
+    public boolean killPids(int[] pids, String pReason) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-            throw new SecurityException("killPidsForMemory only available to the system");
+            throw new SecurityException("killPids only available to the system");
         }
-        
+        String reason = (pReason == null) ? "Unknown" : pReason;
         // XXX Note: don't acquire main activity lock here, because the window
         // manager calls in with its locks held.
         
@@ -8387,7 +8387,7 @@
             if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
                 worstType = HIDDEN_APP_MIN_ADJ;
             }
-            Slog.w(TAG, "Killing processes for memory at adjustment " + worstType);
+            Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
             for (int i=0; i<pids.length; i++) {
                 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
                 if (proc == null) {
@@ -8395,10 +8395,10 @@
                 }
                 int adj = proc.setAdj;
                 if (adj >= worstType) {
-                    Slog.w(TAG, "Killing for memory: " + proc + " (adj "
+                    Slog.w(TAG, "Killing " + reason + " : " + proc + " (adj "
                             + adj + ")");
-                    EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
-                            proc.processName, adj);
+                    EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
+                            proc.processName, adj, reason);
                     killed = true;
                     Process.killProcess(pids[i]);
                 }
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index 0ddcc247..aadd37d 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -58,7 +58,7 @@
 # The activity's onResume has been called.
 30022 am_on_resume_called (Component Name|3)
 # Kill a process to reclaim memory.
-30023 am_kill_for_memory (PID|1|5),(Process Name|3),(OomAdj|1|5)
+30023 am_kill (PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
 # Discard an undelivered serialized broadcast (timeout/ANR/crash)
 30024 am_broadcast_discard_filter (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
 30025 am_broadcast_discard_app (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
diff --git a/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java b/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java
new file mode 100644
index 0000000..636ba21
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.FileUtils;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+
+/**
+ * Tests for {@link com.android.server.EntropyService}
+ */
+public class EntropyServiceTest extends AndroidTestCase {
+
+    public void testInitialWrite() throws Exception {
+        File dir = getContext().getDir("testInitialWrite", Context.MODE_PRIVATE);
+        File file = File.createTempFile("testInitialWrite", "dat", dir);
+        file.deleteOnExit();
+        assertEquals(0, FileUtils.readTextFile(file, 0, null).length());
+
+        // The constructor has the side effect of writing to file
+        new EntropyService("/dev/null", file.getCanonicalPath());
+
+        assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0);
+    }
+}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index b8ea4c0..a284ea5 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -237,8 +237,8 @@
 
     /*
      * TODO(cleanup): It would make some sense if the result of
-     * preprocessing a message to determine the proper encoding (ie
-     * the resulting datastructure from calculateLength) could be
+     * preprocessing a message to determine the proper encoding (i.e.
+     * the resulting data structure from calculateLength) could be
      * passed as an argument to the actual final encoding function.
      * This would better ensure that the logic behind size calculation
      * actually matched the encoding.
@@ -427,7 +427,7 @@
      * @param destinationAddress the address of the destination for the message
      * @param destinationPort the port to deliver the message to at the
      *        destination
-     * @param data the dat for the message
+     * @param data the data for the message
      * @return a <code>SubmitPdu</code> containing the encoded SC
      *         address, if applicable, and the encoded message.
      *         Returns null on encode error.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ae5b1de..f018d107 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -46,7 +46,7 @@
  * {@link android.content.Context#getSystemService
  * Context.getSystemService(Context.TELEPHONY_SERVICE)}.
  * <p>
- * Note that acess to some telephony information is
+ * Note that access to some telephony information is
  * permission-protected. Your application cannot access the protected
  * information unless it has the appropriate permissions declared in
  * its manifest file. Where permissions apply, they are noted in the
@@ -356,7 +356,7 @@
     }
 
     /**
-     * Returns the ISO country code equivilent of the current registered
+     * Returns the ISO country code equivalent of the current registered
      * operator's MCC (Mobile Country Code).
      * <p>
      * Availability: Only when user is registered to a network. Result may be
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 6eea46e..d3a34ec 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -202,7 +202,7 @@
     /**
      * Supply the ICC PIN to the ICC
      *
-     * When the operation is complete, onComplete will be sent to it's
+     * When the operation is complete, onComplete will be sent to its
      * Handler.
      *
      * onComplete.obj will be an AsyncResult
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 358af95..a8f4143 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -585,7 +585,7 @@
 
     /**
      * Utility code to set the system locale if it's not set already
-     * @param langauge Two character language code desired
+     * @param language Two character language code desired
      * @param country Two character country code desired
      *
      *  {@hide}
@@ -694,22 +694,22 @@
 
     public void setTTYMode(int ttyMode, Message onComplete) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("setTTYMode");
     }
 
     public void queryTTYMode(Message onComplete) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("queryTTYMode");
     }
 
     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("enableEnhancedVoicePrivacy");
     }
 
     public void getEnhancedVoicePrivacy(Message onComplete) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("getEnhancedVoicePrivacy");
     }
 
     public void setBandMode(int bandMode, Message response) {
@@ -754,7 +754,7 @@
      * Returns the CDMA ERI icon index to display
      */
     public int getCdmaEriIconIndex() {
-        Log.e(LOG_TAG, "Error! getCdmaEriIconIndex should never be executed in GSM mode");
+        logUnexpectedCdmaMethodCall("getCdmaEriIconIndex");
         return -1;
     }
 
@@ -764,7 +764,7 @@
      * 1 - FLASHING
      */
     public int getCdmaEriIconMode() {
-        Log.e(LOG_TAG, "Error! getCdmaEriIconMode should never be executed in GSM mode");
+        logUnexpectedCdmaMethodCall("getCdmaEriIconMode");
         return -1;
     }
 
@@ -772,82 +772,82 @@
      * Returns the CDMA ERI text,
      */
     public String getCdmaEriText() {
-        Log.e(LOG_TAG, "Error! getCdmaEriText should never be executed in GSM mode");
+        logUnexpectedCdmaMethodCall("getCdmaEriText");
         return "GSM nw, no ERI";
     }
 
     public String getCdmaMin() {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("getCdmaMin");
         return null;
     }
 
     public boolean isMinInfoReady() {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("isMinInfoReady");
         return false;
     }
 
     public String getCdmaPrlVersion(){
         //  This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("getCdmaPrlVersion");
         return null;
     }
 
     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("sendBurstDtmf");
     }
 
     public void exitEmergencyCallbackMode() {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("exitEmergencyCallbackMode");
     }
 
     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("registerForCdmaOtaStatusChange");
     }
 
     public void unregisterForCdmaOtaStatusChange(Handler h) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("unregisterForCdmaOtaStatusChange");
     }
 
     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("registerForSubscriptionInfoReady");
     }
 
     public void unregisterForSubscriptionInfoReady(Handler h) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady");
     }
 
     public  boolean isOtaSpNumber(String dialStr) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("isOtaSpNumber");
         return false;
     }
 
     public void registerForCallWaiting(Handler h, int what, Object obj){
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("registerForCallWaiting");
     }
 
     public void unregisterForCallWaiting(Handler h){
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("unregisterForCallWaiting");
     }
 
     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("registerForEcmTimerReset");
     }
 
     public void unregisterForEcmTimerReset(Handler h) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        logUnexpectedCdmaMethodCall("unregisterForEcmTimerReset");
     }
 
     public void registerForSignalInfo(Handler h, int what, Object obj) {
@@ -908,12 +908,12 @@
 
      public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
          // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+         logUnexpectedCdmaMethodCall("setOnEcbModeExitResponse");
      }
 
      public void unsetOnEcbModeExitResponse(Handler h){
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+         logUnexpectedCdmaMethodCall("unsetOnEcbModeExitResponse");
      }
 
     public String getInterfaceName(String apnType) {
@@ -984,7 +984,7 @@
     }
 
     /**
-     * Notifiy registrants of a new ringing Connection.
+     * Notify registrants of a new ringing Connection.
      * Subclasses of Phone probably want to replace this with a
      * version scoped to their packages
      */
@@ -1017,4 +1017,13 @@
                     + " mCallRingContinueToken=" + mCallRingContinueToken);
         }
     }
+
+    /**
+     * Common error logger method for unexpected calls to CDMA-only methods.
+     */
+    private void logUnexpectedCdmaMethodCall(String name)
+    {
+        Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
+                "called, CDMAPhone inactive.");
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index 4a4282fc..764d12e 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -109,6 +109,12 @@
     /** Stop the sending */
     static final protected int EVENT_STOP_SENDING = 10;
 
+    /** Memory status reporting is acknowledged by RIL */
+    static final protected int EVENT_REPORT_MEMORY_STATUS_DONE = 11;
+
+    /** Radio is ON */
+    static final protected int EVENT_RADIO_ON = 12;
+
     protected Phone mPhone;
     protected Context mContext;
     protected ContentResolver mResolver;
@@ -152,6 +158,7 @@
     private SmsMessageBase.SubmitPduBase mSubmitPduBase;
 
     protected boolean mStorageAvailable = true;
+    protected boolean mReportMemoryStatusPending = false;
 
     protected static int getNextConcatenatedRef() {
         sConcatenatedRef += 1;
@@ -235,6 +242,7 @@
         mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);
         mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
         mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null);
+        mCm.registerForOn(this, EVENT_RADIO_ON, null);
 
         // Don't always start message ref at 0.
         sConcatenatedRef = new Random().nextInt(256);
@@ -253,6 +261,7 @@
         mCm.unSetOnNewSMS(this);
         mCm.unSetOnSmsStatus(this);
         mCm.unSetOnIccSmsFull(this);
+        mCm.unregisterForOn(this);
     }
 
     protected void finalize() {
@@ -370,6 +379,26 @@
                 removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
             }
             break;
+
+        case EVENT_REPORT_MEMORY_STATUS_DONE:
+            ar = (AsyncResult)msg.obj;
+            if (ar.exception != null) {
+                mReportMemoryStatusPending = true;
+                Log.v(TAG, "Memory status report to modem pending : mStorageAvailable = "
+                        + mStorageAvailable);
+            } else {
+                mReportMemoryStatusPending = false;
+            }
+            break;
+
+        case EVENT_RADIO_ON:
+            if (mReportMemoryStatusPending) {
+                Log.v(TAG, "Sending pending memory status report : mStorageAvailable = "
+                        + mStorageAvailable);
+                mCm.reportSmsMemoryStatus(mStorageAvailable,
+                        obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
+            }
+            break;
         }
     }
 
@@ -940,10 +969,10 @@
             public void onReceive(Context context, Intent intent) {
                 if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_LOW)) {
                     mStorageAvailable = false;
-                    mCm.reportSmsMemoryStatus(false, null);
+                    mCm.reportSmsMemoryStatus(false, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
                 } else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_OK)) {
                     mStorageAvailable = true;
-                    mCm.reportSmsMemoryStatus(true, null);
+                    mCm.reportSmsMemoryStatus(true, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
                 } else {
                     // Assume the intent is one of the SMS receive intents that
                     // was sent as an ordered broadcast.  Check result and ACK.
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index dd7a169..6975c70 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -93,6 +93,9 @@
     protected void setUp() throws Exception {
         super.setUp();
         mOrigState = getMediaState();
+        if (!mountMedia()) {
+            Log.i(TAG, "sdcard not mounted? Some of these tests might fail");
+        }
     }
 
     @Override
diff --git a/tests/ConnectivityManagerTest/Android.mk b/tests/ConnectivityManagerTest/Android.mk
new file mode 100644
index 0000000..bd773d0
--- /dev/null
+++ b/tests/ConnectivityManagerTest/Android.mk
@@ -0,0 +1,30 @@
+# Copyright 2010, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := ConnectivityManagerTest
+
+#LOCAL_INSTRUMENTATION_FOR := connectivitymanagertest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ConnectivityManagerTest/AndroidManifest.xml b/tests/ConnectivityManagerTest/AndroidManifest.xml
new file mode 100644
index 0000000..76b58e1
--- /dev/null
+++ b/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.connectivitymanagertest">
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="ConnectivityManagerTestActivity"
+          android:label="CMTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+    </application>
+    <!--
+    This declares that this app uses the instrumentation test runner targeting
+    the package of browserpowertest. To run the tests use the command:
+    "adb shell am instrument -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner"
+    -->
+    <instrumentation android:name=".ConnectivityManagerTestRunner"
+        android:targetPackage="com.android.connectivitymanagertest"
+        android:label="Test runner for Connectivity Manager Tests"
+    />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+
+</manifest>
diff --git a/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
new file mode 100644
index 0000000..1dffa02
--- /dev/null
+++ b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -0,0 +1,329 @@
+package com.android.connectivitymanagertest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import java.util.List;
+import android.widget.LinearLayout;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+
+
+/**
+ * An activity registered with connectivity manager broadcast
+ * provides network connectivity information and
+ * can be used to set device states: Cellular, Wifi, Airplane mode.
+ */
+public class ConnectivityManagerTestActivity extends Activity {
+
+    public static final String LOG_TAG = "ConnectivityManagerTestActivity";
+    public static final int WAIT_FOR_SCAN_RESULT = 5 * 1000; //5 seconds
+    public static final int WIFI_SCAN_TIMEOUT = 20 * 1000;
+    public ConnectivityReceiver mConnectivityReceiver = null;
+    public WifiReceiver mWifiReceiver = null;
+    /*
+     * Track network connectivity information
+     */
+    public State mState;
+    public NetworkInfo mNetworkInfo;
+    public NetworkInfo mOtherNetworkInfo;
+    public boolean mIsFailOver;
+    public String mReason;
+    public boolean mScanResultIsAvailable = false;
+    public ConnectivityManager mCM;
+
+    /*
+     * Control Wifi States
+     */
+    public WifiManager mWifiManager;
+
+    /*
+     * Verify connectivity state
+     */
+    public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE;
+    NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
+
+    /**
+     * A wrapper of a broadcast receiver which provides network connectivity information
+     * for all kinds of network: wifi, mobile, etc.
+     */
+    private class ConnectivityReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
+                return;
+            }
+
+            boolean noConnectivity =
+                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+
+            if (noConnectivity) {
+                mState = State.DISCONNECTED;
+            } else {
+                mState = State.CONNECTED;
+            }
+
+            mNetworkInfo = (NetworkInfo)
+                intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+
+            mOtherNetworkInfo = (NetworkInfo)
+                intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
+
+            mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
+            mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
+            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
+            if (mOtherNetworkInfo != null) {
+                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
+            }
+        }
+    }
+
+    private class WifiReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (!action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+                Log.v(LOG_TAG, "onReceive() is calleld with " + intent);
+                return;
+            }
+            notifyScanResult();
+        }
+    }
+
+    public ConnectivityManagerTestActivity() {
+        mState = State.UNKNOWN;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.v(LOG_TAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
+
+        // Create a simple layout
+        LinearLayout contentView = new LinearLayout(this);
+        contentView.setOrientation(LinearLayout.VERTICAL);
+        setContentView(contentView);
+        setTitle("ConnectivityManagerTestActivity");
+
+        mConnectivityReceiver = new ConnectivityReceiver();
+        // register a connectivity receiver for CONNECTIVITY_ACTION;
+        registerReceiver(mConnectivityReceiver,
+                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+
+        mWifiReceiver = new WifiReceiver();
+        registerReceiver(mWifiReceiver,
+                new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
+        // Get an instance of ConnectivityManager
+        mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+        // Get an instance of WifiManager
+        mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
+        initializeNetworkStates();
+
+        if (mWifiManager.isWifiEnabled()) {
+            Log.v(LOG_TAG, "Clear Wifi before we start the test.");
+            clearWifi();
+        }
+     }
+
+    // for each network type, initialize network states to UNKNOWN, and no verification flag is set
+    public void initializeNetworkStates() {
+        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
+            connectivityState[networkType] =  new NetworkState();
+            Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
+                    connectivityState[networkType].toString());
+        }
+    }
+
+    // deposit a network state
+    public void recordNetworkState(int networkType, State networkState) {
+        Log.v(LOG_TAG, "record network state for network " +  networkType +
+                " state is " + networkState);
+        connectivityState[networkType].recordState(networkState);
+    }
+
+    // set the state transition criteria
+    public void setStateTransitionCriteria(int networkType, State initState,
+            int transitionDir, State targetState) {
+        connectivityState[networkType].setStateTransitionCriteria(
+                initState, transitionDir, targetState);
+    }
+
+    // Validate the states recorded
+    public boolean validateNetworkStates(int networkType) {
+        Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
+        return connectivityState[networkType].validateStateTransition();
+    }
+
+    // return result from network state validation
+    public String getTransitionFailureReason(int networkType) {
+        Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
+                connectivityState[networkType].toString());
+        return connectivityState[networkType].getReason();
+    }
+
+    private void notifyScanResult() {
+        synchronized (this) {
+            Log.v(LOG_TAG, "notify that scan results are available");
+            this.notify();
+        }
+    }
+
+    // Return true if device is currently connected to mobile network
+    public boolean isConnectedToMobile() {
+        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
+    }
+
+    // Return true if device is currently connected to Wifi
+    public boolean isConnectedToWifi() {
+        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
+    }
+
+    public boolean enableWifi() {
+        return mWifiManager.setWifiEnabled(true);
+    }
+
+    /**
+     * Associate the device to given SSID
+     * If the device is already associated with a WiFi, disconnect and forget it,
+     * We don't verify whether the connection is successful or not, leave this to the test
+     */
+    public boolean connectToWifi(String knownSSID) {
+        //If Wifi is not enabled, enable it
+        if (!mWifiManager.isWifiEnabled()) {
+            Log.v(LOG_TAG, "Wifi is not enabled, enable it");
+            mWifiManager.setWifiEnabled(true);
+        }
+
+        List<ScanResult> netList = mWifiManager.getScanResults();
+        if (netList == null) {
+            // if no scan results are available, start active scan
+            mWifiManager.startScanActive();
+            mScanResultIsAvailable = false;
+            long startTime = System.currentTimeMillis();
+            while (!mScanResultIsAvailable) {
+                if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
+                    return false;
+                }
+                // wait for the scan results to be available
+                synchronized (this) {
+                    // wait for the scan result to be available
+                    try {
+                        this.wait(WAIT_FOR_SCAN_RESULT);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    if ((mWifiManager.getScanResults() == null) ||
+                            (mWifiManager.getScanResults().size() <= 0)) {
+                        continue;
+                    }
+                    mScanResultIsAvailable = true;
+                }
+            }
+        }
+
+        netList = mWifiManager.getScanResults();
+        for (int i = 0; i < netList.size(); i++) {
+            ScanResult sr= netList.get(i);
+            if (sr.SSID.equals(knownSSID)) {
+                Log.v(LOG_TAG, "found " + knownSSID + " in the scan result list");
+                WifiConfiguration config = new WifiConfiguration();
+                config.SSID = sr.SSID;
+                config.allowedKeyManagement.set(KeyMgmt.NONE);
+                int networkId = mWifiManager.addNetwork(config);
+                mWifiManager.saveConfiguration();
+                // Connect to network by disabling others.
+                mWifiManager.enableNetwork(networkId, true);
+                mWifiManager.reconnect();
+                break;
+           }
+        }
+
+        List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
+        if (netConfList.size() <= 0) {
+            Log.v(LOG_TAG, knownSSID + " is not available");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Disable Wifi
+     * @return true if Wifi is disabled successfully
+     */
+    public boolean disableWiFi() {
+        return mWifiManager.setWifiEnabled(false);
+    }
+
+    /**
+     * Disconnect from the current Wifi and clear the configuration list
+     */
+    public boolean clearWifi() {
+       if (mWifiManager.isWifiEnabled()) {
+            //remove the current network Id
+            int curNetworkId = mWifiManager.getConnectionInfo().getNetworkId();
+            mWifiManager.removeNetwork(curNetworkId);
+            mWifiManager.saveConfiguration();
+
+            // remove other saved networks
+            List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
+            if (netConfList != null) {
+                Log.v(LOG_TAG, "remove configured network ids");
+                for (int i = 0; i < netConfList.size(); i++) {
+                    WifiConfiguration conf = new WifiConfiguration();
+                    conf = netConfList.get(i);
+                    mWifiManager.removeNetwork(conf.networkId);
+                }
+            }
+            mWifiManager.saveConfiguration();
+            // disable Wifi
+            if (!mWifiManager.setWifiEnabled(false)) {
+                return false;
+            }
+            // wait for the actions to be completed
+            try {
+                Thread.sleep(5*1000);
+            } catch (InterruptedException e) {}
+        }
+        return true;
+    }
+
+    /**
+     * Set airplane mode
+     */
+    public void setAirplaneMode(Context context, boolean enableAM) {
+        //set the airplane mode
+        Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+                enableAM ? 1 : 0);
+        // Post the intent
+        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.putExtra("state", enableAM);
+        context.sendBroadcast(intent);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        //Unregister receiver
+        if (mConnectivityReceiver != null) {
+            unregisterReceiver(mConnectivityReceiver);
+        }
+        if (mWifiReceiver != null) {
+            unregisterReceiver(mWifiReceiver);
+        }
+        Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+    }
+}
diff --git a/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
new file mode 100644
index 0000000..3affa65
--- /dev/null
+++ b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -0,0 +1,43 @@
+package com.android.connectivitymanagertest;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import android.util.Log;
+import com.android.connectivitymanagertest.functional.ConnectivityManagerMobileTest;
+
+import junit.framework.TestSuite;
+
+/**
+ * Instrumentation Test Runner for all connectivity manager tests.
+ *
+ * To run the connectivity manager tests:
+ *
+ * adb shell am instrument \
+ *     -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
+ */
+
+public class ConnectivityManagerTestRunner extends InstrumentationTestRunner {
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(ConnectivityManagerMobileTest.class);
+        return suite;
+    }
+
+    @Override
+    public ClassLoader getLoader() {
+        return ConnectivityManagerTestRunner.class.getClassLoader();
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        String testSSID = (String) icicle.get("ssid");
+        if (testSSID != null) {
+            TEST_SSID = testSSID;
+        }
+    }
+
+    public String TEST_SSID = "GoogleGuest";
+}
diff --git a/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
new file mode 100644
index 0000000..925120e
--- /dev/null
+++ b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
@@ -0,0 +1,177 @@
+package com.android.connectivitymanagertest;
+
+import android.net.NetworkInfo.State;
+import android.util.Log;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class NetworkState {
+    public static final int TO_DISCONNECTION = 0; // transition to disconnection
+    public static final int TO_CONNECTION = 1; // transition to connection
+    public static final int DO_NOTHING = -1;   // no state change
+    private final String LOG_TAG = "NetworkState";
+    private List<State> mStateDepository;
+    private State mTransitionTarget;
+    private int mTransitionDirection;
+    private String mReason = null;         // record mReason of state transition failure
+
+    public NetworkState() {
+        mStateDepository = new ArrayList<State>();
+        mTransitionDirection = DO_NOTHING;
+        mTransitionTarget = State.UNKNOWN;
+    }
+
+    public NetworkState(State currentState) {
+        mStateDepository = new ArrayList<State>();
+        mStateDepository.add(currentState);
+        mTransitionDirection = DO_NOTHING;
+        mTransitionTarget = State.UNKNOWN;
+    }
+
+    // Reinitialize the network state
+    public void resetNetworkState() {
+        mStateDepository.clear();
+        mTransitionDirection = DO_NOTHING;
+        mTransitionTarget = State.UNKNOWN;
+    }
+
+    // set the transition criteria, transitionDir could be:
+    // DO_NOTHING, TO_CONNECTION, TO_DISCONNECTION
+    public void setStateTransitionCriteria(State initState, int transitionDir, State targetState) {
+        if (!mStateDepository.isEmpty()) {
+            mStateDepository.clear();
+        }
+        mStateDepository.add(initState);
+        mTransitionDirection = transitionDir;
+        mTransitionTarget = targetState;
+        Log.v(LOG_TAG, "setStateTransitionCriteria: " + printStates());
+    }
+
+    public void recordState(State currentState) {
+        mStateDepository.add(currentState);
+    }
+
+    // Verify state transition
+    public boolean validateStateTransition() {
+        Log.v(LOG_TAG, "print state depository: " + printStates());
+        if (mTransitionDirection == DO_NOTHING) {
+            if (mStateDepository.isEmpty()) {
+                Log.v(LOG_TAG, "no state is recorded");
+                mReason = "no state is recorded.";
+                return false;
+            } else if (mStateDepository.size() > 1) {
+                Log.v(LOG_TAG, "no broadcast is expected, " +
+                        "instead broadcast is probably received");
+                mReason = "no broadcast is expected, instead broadcast is probably received";
+                return false;
+            } else if (mStateDepository.get(0) != mTransitionTarget) {
+                Log.v(LOG_TAG, mTransitionTarget + " is expected, but it is " +
+                        mStateDepository.get(0));
+                mReason = mTransitionTarget + " is expected, but it is " + mStateDepository.get(0);
+                return false;
+            }
+            return true;
+        } else if (mTransitionDirection == TO_CONNECTION) {
+            Log.v(LOG_TAG, "transition to CONNECTED");
+            return transitToConnection();
+        } else {
+            Log.v(LOG_TAG, "transition to DISCONNECTED");
+            return transitToDisconnection();
+        }
+    }
+
+    /*
+     * Transition from CONNECTED -> DISCONNECTED:
+     *    CONNECTED->DISCONNECTING->DISCONNECTED
+     * return false if any state transition is not valid and save a message in mReason
+     */
+    public boolean transitToDisconnection () {
+        mReason = "states: " + printStates();
+        if (mStateDepository.get(0) != State.CONNECTED) {
+            mReason += " initial state should be CONNECTED, but it is " +
+                    mStateDepository.get(0) + ".";
+            return false;
+        }
+        State lastState = mStateDepository.get(mStateDepository.size() - 1);
+        if ( lastState != mTransitionTarget) {
+            mReason += " the last state should be DISCONNECTED, but it is " + lastState;
+            return false;
+        }
+        for (int i = 1; i < mStateDepository.size() - 1; i++) {
+            State preState = mStateDepository.get(i-1);
+            State curState = mStateDepository.get(i);
+            if ((preState == State.CONNECTED) && ((curState == State.DISCONNECTING) ||
+                    (curState == State.DISCONNECTED))) {
+                continue;
+            } else if ((preState == State.DISCONNECTING) && (curState == State.DISCONNECTED)) {
+                continue;
+            } else if ((preState == State.DISCONNECTED) && (curState == State.DISCONNECTED)) {
+                continue;
+            } else {
+                mReason += " Transition state from " + preState.toString() + " to " +
+                        curState.toString() + " is not valid.";
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // DISCONNECTED->CONNECTING->CONNECTED
+    public boolean transitToConnection() {
+        mReason = "states: " + printStates();
+        if (mStateDepository.get(0) != State.DISCONNECTED) {
+            mReason += " initial state should be DISCONNECTED, but it is " +
+                    mStateDepository.get(0) + ".";
+            return false;
+        }
+        State lastState = mStateDepository.get(mStateDepository.size() - 1);
+        if ( lastState != mTransitionTarget) {
+            mReason += " the last state should be CONNECTED, but it is " + lastState;
+            return false;
+        }
+        for (int i = 1; i < mStateDepository.size(); i++) {
+            State preState = mStateDepository.get(i-1);
+            State curState = mStateDepository.get(i);
+            if ((preState == State.DISCONNECTED) && ((curState == State.CONNECTING) ||
+                    (curState == State.CONNECTED))) {
+                continue;
+            } else if ((preState == State.CONNECTING) && (curState == State.CONNECTED)) {
+                continue;
+            } else if ((preState == State.CONNECTED) && (curState == State.CONNECTED)) {
+                continue;
+            } else {
+                mReason += " Transition state from " + preState.toString() + " to " +
+                        curState.toString() + " is not valid.";
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public List<State> getTransitionStates() {
+        return mStateDepository;
+    }
+
+    // return state failure mReason
+    public String getReason() {
+        return mReason;
+    }
+
+    public String printStates() {
+        StringBuilder stateBuilder = new StringBuilder("");
+        for (int i = 0; i < mStateDepository.size(); i++) {
+            stateBuilder.append(" ").append(mStateDepository.get(i).toString()).append("->");
+        }
+        return stateBuilder.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(" ");
+        builder.append("mTransitionDirection: ").append(Integer.toString(mTransitionDirection)).
+                append("; ").append("states:").
+                append(printStates()).append("; ");
+        return builder.toString();
+    }
+}
diff --git a/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
new file mode 100644
index 0000000..ab81bb8
--- /dev/null
+++ b/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -0,0 +1,135 @@
+package com.android.connectivitymanagertest.functional;
+
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+
+import android.content.Intent;
+import android.content.Context;
+import android.app.Instrumentation;
+import android.os.Handler;
+import android.os.Message;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.net.NetworkInfo.DetailedState;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.ActivityInstrumentationTestCase2;
+import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
+import com.android.connectivitymanagertest.NetworkState;
+import android.util.Log;
+import junit.framework.*;
+
+public class ConnectivityManagerMobileTest
+    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+
+    private static final String LOG_TAG = "ConnectivityManagerMobileTest";
+    private static final String PKG_NAME = "com.android.connectivitymanagertest";
+    private static final long WIFI_CONNECTION_TIMEOUT = 30 * 1000;
+    private static final long WIFI_NOTIFICATION_TIMEOUT = 10 * 1000;
+    private String TEST_ACCESS_POINT;
+    private ConnectivityManagerTestActivity cmActivity;
+
+    public ConnectivityManagerMobileTest() {
+        super(PKG_NAME, ConnectivityManagerTestActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        cmActivity = getActivity();
+        ConnectivityManagerTestRunner mRunner =
+                (ConnectivityManagerTestRunner)getInstrumentation();
+        TEST_ACCESS_POINT = mRunner.TEST_SSID;
+        // Each test case will start with cellular connection
+        verifyCellularConnection();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        // clear Wifi after each test case
+        cmActivity.clearWifi();
+        cmActivity.finish();
+        Log.v(LOG_TAG, "tear down ConnectivityManager test activity");
+        super.tearDown();
+    }
+
+    // help function to verify 3G connection
+    public void verifyCellularConnection() {
+        NetworkInfo extraNetInfo = cmActivity.mNetworkInfo;
+        assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
+            extraNetInfo.getType());
+        assertTrue("not connected to cellular network", extraNetInfo.isConnected());
+        assertTrue("no data connection", cmActivity.mState.equals(State.CONNECTED));
+    }
+
+    // Test case 1: Test enabling Wifi without associating with any AP
+    @LargeTest
+    public void test3GToWifiNotification() {
+        // As Wifi stays in DISCONNECTED, the connectivity manager will not broadcast
+        // any network connectivity event for Wifi
+        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE, networkInfo.getState(),
+                NetworkState.DO_NOTHING, State.CONNECTED);
+        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+                NetworkState.DO_NOTHING, State.DISCONNECTED);
+        // Eanble Wifi
+        cmActivity.enableWifi();
+        try {
+            Thread.sleep(WIFI_NOTIFICATION_TIMEOUT);
+        } catch (Exception e) {
+            Log.v(LOG_TAG, "exception: " + e.toString());
+        }
+
+        // validate state and broadcast
+        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+            Log.v(LOG_TAG, "the state for WIFI is changed");
+            Log.v(LOG_TAG, "reason: " +
+                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+            assertTrue(false);
+        }
+        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+            Log.v(LOG_TAG, "the state for MOBILE is changed");
+            Log.v(LOG_TAG, "reason: " +
+                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+            assertTrue(false);
+        }
+        // Verify that the device is still connected to MOBILE
+        verifyCellularConnection();
+    }
+
+    // Test case 2: test connection to a given AP
+    @LargeTest
+    public void testConnectToWifi() {
+        //Prepare for connectivity verification
+        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE, networkInfo.getState(),
+                NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
+        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+                NetworkState.TO_CONNECTION, State.CONNECTED);
+
+        // Enable Wifi and connect to a test access point
+        assertTrue("failed to connect to " + TEST_ACCESS_POINT,
+                cmActivity.connectToWifi(TEST_ACCESS_POINT));
+        try {
+            Thread.sleep(WIFI_CONNECTION_TIMEOUT);
+        } catch (Exception e) {
+            Log.v(LOG_TAG, "exception: " + e.toString());
+        }
+
+        // validate states
+        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+            Log.v(LOG_TAG, "Wifi state transition validation failed.");
+            Log.v(LOG_TAG, "reason: " +
+                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+            assertTrue(false);
+        }
+        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+            Log.v(LOG_TAG, "Mobile state transition validation failed.");
+            Log.v(LOG_TAG, "reason: " +
+                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+            assertTrue(false);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index abae65d..80b8aedfa 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -54,10 +54,11 @@
 import android.database.ContentObserver;
 import com.android.internal.app.IBatteryStats;
 
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Set;
 import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Track the state of Wifi connectivity. All event handling is done here,
@@ -282,8 +283,13 @@
      *         {@link WifiManager#WIFI_STATE_ENABLED},
      *         {@link WifiManager#WIFI_STATE_ENABLING},
      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
+     *
+     * getWifiState() is not synchronized to make sure it's always fast,
+     * even when the instance lock is held on other slow operations.
+     * Use a atomic variable for state.
      */
-    private int mWifiState;
+    private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_UNKNOWN);
+
     // Wi-Fi run states:
     private static final int RUN_STATE_STARTING = 1;
     private static final int RUN_STATE_RUNNING  = 2;
@@ -785,8 +791,8 @@
             case EVENT_SUPPLICANT_DISCONNECT:
                 mRunState = RUN_STATE_STOPPED;
                 noteRunState();
-                boolean died = mWifiState != WIFI_STATE_DISABLED &&
-                               mWifiState != WIFI_STATE_DISABLING;
+                boolean died = mWifiState.get() != WIFI_STATE_DISABLED &&
+                               mWifiState.get() != WIFI_STATE_DISABLING;
                 if (died) {
                     if (LOCAL_LOGD) Log.v(TAG, "Supplicant died unexpectedly");
                 } else {
@@ -1504,12 +1510,12 @@
         return true;
     }
 
-    public synchronized int getWifiState() {
-        return mWifiState;
+    public int getWifiState() {
+        return mWifiState.get();
     }
 
-    public synchronized void setWifiState(int wifiState) {
-        mWifiState = wifiState;
+    public void setWifiState(int wifiState) {
+        mWifiState.set(wifiState);
     }
 
    /**
@@ -1588,7 +1594,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean ping() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.pingCommand();
@@ -1601,7 +1607,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean scan(boolean forceActive) {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.scanCommand(forceActive);
@@ -1617,7 +1623,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean setScanResultHandling(int mode) {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.setScanResultHandlingCommand(mode);
@@ -1631,7 +1637,7 @@
      * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
      */
     public synchronized String scanResults() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return null;
         }
         return WifiNative.scanResultsCommand();
@@ -1643,7 +1649,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean setScanMode(boolean isScanModeActive) {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         if (mIsScanModeActive != isScanModeActive) {
@@ -1658,7 +1664,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean disconnect() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.disconnectCommand();
@@ -1670,7 +1676,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean reconnectCommand() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.reconnectCommand();
@@ -1682,7 +1688,7 @@
      * @return network id of the new network
      */
     public synchronized int addNetwork() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return -1;
         }
         return WifiNative.addNetworkCommand();
@@ -1695,7 +1701,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean removeNetwork(int networkId) {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return mDisconnectExpected = WifiNative.removeNetworkCommand(networkId);
@@ -1709,7 +1715,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean enableNetwork(int netId, boolean disableOthers) {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.enableNetworkCommand(netId, disableOthers);
@@ -1722,7 +1728,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean disableNetwork(int netId) {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.disableNetworkCommand(netId);
@@ -1734,7 +1740,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean reassociate() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.reassociateCommand();
@@ -1748,7 +1754,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean addToBlacklist(String bssid) {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.addToBlacklistCommand(bssid);
@@ -1760,7 +1766,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean clearBlacklist() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.clearBlacklistCommand();
@@ -1772,7 +1778,7 @@
      * @return list of networks or null on failure
      */
     public synchronized String listNetworks() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return null;
         }
         return WifiNative.listNetworksCommand();
@@ -1786,7 +1792,7 @@
      * @return value corresponding to key
      */
     public synchronized String getNetworkVariable(int netId, String name) {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return null;
         }
         return WifiNative.getNetworkVariableCommand(netId, name);
@@ -1801,7 +1807,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean setNetworkVariable(int netId, String name, String value) {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.setNetworkVariableCommand(netId, name, value);
@@ -1821,7 +1827,7 @@
      *  ip_address=X.X.X.X
      */
     public synchronized String status() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return null;
         }
         return WifiNative.statusCommand();
@@ -1833,7 +1839,7 @@
      * @return RSSI value, -1 on failure
      */
     public synchronized int getRssi() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return -1;
         }
         return WifiNative.getRssiApproxCommand();
@@ -1845,7 +1851,7 @@
      * @return RSSI value, -1 on failure
      */
     public synchronized int getRssiApprox() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return -1;
         }
         return WifiNative.getRssiApproxCommand();
@@ -1857,7 +1863,7 @@
      * @return link speed, -1 on failure
      */
     public synchronized int getLinkSpeed() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return -1;
         }
         return WifiNative.getLinkSpeedCommand();
@@ -1869,7 +1875,7 @@
      * @return MAC address, null on failure
      */
     public synchronized String getMacAddress() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return null;
         }
         return WifiNative.getMacAddressCommand();
@@ -1881,7 +1887,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean startDriver() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.startDriverCommand();
@@ -1893,7 +1899,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean stopDriver() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.stopDriverCommand();
@@ -1905,7 +1911,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean startPacketFiltering() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.startPacketFiltering();
@@ -1917,7 +1923,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean stopPacketFiltering() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.stopPacketFiltering();
@@ -1931,7 +1937,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean setPowerMode(int mode) {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.setPowerModeCommand(mode);
@@ -1944,7 +1950,7 @@
      * the number of channels is invalid.
      */
     public synchronized boolean setNumAllowedChannels() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         try {
@@ -1969,7 +1975,7 @@
      * {@code numChannels} is outside the valid range.
      */
     public synchronized boolean setNumAllowedChannels(int numChannels) {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         mNumAllowedChannels = numChannels;
@@ -1982,7 +1988,7 @@
      * @return channel count, -1 on failure
      */
     public synchronized int getNumAllowedChannels() {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return -1;
         }
         return WifiNative.getNumAllowedChannelsCommand();
@@ -1998,7 +2004,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean setBluetoothCoexistenceMode(int mode) {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return false;
         }
         return WifiNative.setBluetoothCoexistenceModeCommand(mode);
@@ -2012,7 +2018,7 @@
      * @param isBluetoothPlaying whether to enable or disable this mode
      */
     public synchronized void setBluetoothScanMode(boolean isBluetoothPlaying) {
-        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
             return;
         }
         WifiNative.setBluetoothCoexistenceScanModeCommand(isBluetoothPlaying);
@@ -2024,7 +2030,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean saveConfig() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.saveConfigCommand();
@@ -2036,7 +2042,7 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public synchronized boolean reloadConfig() {
-        if (mWifiState != WIFI_STATE_ENABLED) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
         return WifiNative.reloadConfigCommand();