Merge "print finalizer warning before closing the cursor in finalize"
diff --git a/api/current.xml b/api/current.xml
index 9dc2218..4af2a43 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"
@@ -88376,7 +88413,7 @@
  static="true"
  final="false"
  deprecated="not deprecated"
- visibility="private"
+ visibility="public"
 >
 <method name="startDownloadByUri"
  return="long"
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 596ca9d..adadfeb 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -168,6 +168,29 @@
             return true;
         }
 
+        case START_ACTIVITY_WITH_CONFIG_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder b = data.readStrongBinder();
+            IApplicationThread app = ApplicationThreadNative.asInterface(b);
+            Intent intent = Intent.CREATOR.createFromParcel(data);
+            String resolvedType = data.readString();
+            Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR);
+            int grantedMode = data.readInt();
+            IBinder resultTo = data.readStrongBinder();
+            String resultWho = data.readString();    
+            int requestCode = data.readInt();
+            boolean onlyIfNeeded = data.readInt() != 0;
+            boolean debug = data.readInt() != 0;
+            Configuration config = Configuration.CREATOR.createFromParcel(data);
+            int result = startActivityWithConfig(app, intent, resolvedType,
+                    grantedUriPermissions, grantedMode, resultTo, resultWho,
+                    requestCode, onlyIfNeeded, debug, config);
+            reply.writeNoException();
+            reply.writeInt(result);
+            return true;
+        }
+
         case START_ACTIVITY_INTENT_SENDER_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -1295,6 +1318,32 @@
         data.recycle();
         return result;
     }
+    public int startActivityWithConfig(IApplicationThread caller, Intent intent,
+            String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
+            IBinder resultTo, String resultWho,
+            int requestCode, boolean onlyIfNeeded,
+            boolean debug, Configuration config) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
+        intent.writeToParcel(data, 0);
+        data.writeString(resolvedType);
+        data.writeTypedArray(grantedUriPermissions, 0);
+        data.writeInt(grantedMode);
+        data.writeStrongBinder(resultTo);
+        data.writeString(resultWho);
+        data.writeInt(requestCode);
+        data.writeInt(onlyIfNeeded ? 1 : 0);
+        data.writeInt(debug ? 1 : 0);
+        config.writeToParcel(data, 0);
+        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int result = reply.readInt();
+        reply.recycle();
+        data.recycle();
+        return result;
+    }
     public int startActivityIntentSender(IApplicationThread caller,
             IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 30feae1..ea0e952 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -88,6 +88,10 @@
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo, String resultWho, int requestCode,
             boolean onlyIfNeeded, boolean debug) throws RemoteException;
+    public int startActivityWithConfig(IApplicationThread caller,
+            Intent intent, String resolvedType, Uri[] grantedUriPermissions,
+            int grantedMode, IBinder resultTo, String resultWho, int requestCode,
+            boolean onlyIfNeeded, boolean debug, Configuration newConfig) throws RemoteException;
     public int startActivityIntentSender(IApplicationThread caller,
             IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
@@ -503,4 +507,5 @@
     int IS_USER_A_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+103;
     int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104;
     int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105;
+    int START_ACTIVITY_WITH_CONFIG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+106;
 }
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/ContentValues.java b/core/java/android/content/ContentValues.java
index c04625d..75787cd 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -66,7 +66,7 @@
      * Creates a set of values copied from the given HashMap. This is used
      * by the Parcel unmarshalling code.
      *
-     * @param from the values to start with
+     * @param values the values to start with
      * {@hide}
      */
     private ContentValues(HashMap<String, Object> values) {
@@ -248,7 +248,7 @@
      */
     public String getAsString(String key) {
         Object value = mValues.get(key);
-        return value != null ? mValues.get(key).toString() : null;
+        return value != null ? value.toString() : null;
     }
 
     /**
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/Downloads.java b/core/java/android/net/Downloads.java
index 72106c8..3867385 100644
--- a/core/java/android/net/Downloads.java
+++ b/core/java/android/net/Downloads.java
@@ -469,7 +469,7 @@
     /**
      * Base class with common functionality for the various download classes
      */
-    private static class DownloadBase {
+    public static class DownloadBase {
         /** @hide */
         DownloadBase() {}
 
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/provider/Settings.java b/core/java/android/provider/Settings.java
index 13f8780..2ba38c23 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3274,6 +3274,14 @@
                 INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF;
 
         /**
+         * The current night mode that has been selected by the user.  Owned
+         * and controlled by UiModeManagerService.  Constants are as per
+         * UiModeManager.
+         * @hide
+         */
+        public static final String UI_NIGHT_MODE = "ui_night_mode";
+        
+        /**
          * @hide
          */
         public static final String[] SETTINGS_TO_BACKUP = {
@@ -3299,7 +3307,8 @@
             MOUNT_PLAY_NOTIFICATION_SND,
             MOUNT_UMS_AUTOSTART,
             MOUNT_UMS_PROMPT,
-            MOUNT_UMS_NOTIFY_ENABLED
+            MOUNT_UMS_NOTIFY_ENABLED,
+            UI_NIGHT_MODE
         };
 
         /**
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/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/ViewManager.java b/core/java/android/webkit/ViewManager.java
index fc5c425..23cf6b8 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -28,6 +28,7 @@
     private final ArrayList<ChildView> mChildren = new ArrayList<ChildView>();
     private boolean mHidden;
     private boolean mReadyToDraw;
+    private boolean mZoomInProgress = false;
 
     // Threshold at which a surface is prevented from further increasing in size
     private final int MAX_SURFACE_THRESHOLD;
@@ -39,11 +40,6 @@
         int height;
         View mView; // generic view to show
 
-        /* set to true if the view is a surface and it has exceeded the pixel
-           threshold specified in MAX_SURFACE_THRESHOLD.
-         */
-        boolean isFixedSize = false;
-
         ChildView() {
         }
 
@@ -66,19 +62,17 @@
                     // already attached, just set the new LayoutParams,
                     // otherwise attach the view and add it to the list of
                     // children.
-                    AbsoluteLayout.LayoutParams lp = computeLayout(ChildView.this);
+                    requestLayout(ChildView.this);
 
-                    if (mView.getParent() != null) {
-                        mView.setLayoutParams(lp);
-                    } else {
-                        attachViewOnUIThread(lp);
+                    if (mView.getParent() == null) {
+                        attachViewOnUIThread();
                     }
                 }
             });
         }
 
-        private void attachViewOnUIThread(AbsoluteLayout.LayoutParams lp) {
-            mWebView.addView(mView, lp);
+        private void attachViewOnUIThread() {
+            mWebView.addView(mView);
             mChildren.add(this);
             if (!mReadyToDraw) {
                 mView.setVisibility(View.GONE);
@@ -146,35 +140,87 @@
     /**
      * This should only be called from the UI thread.
      */
-    private AbsoluteLayout.LayoutParams computeLayout(ChildView v) {
+    private void requestLayout(ChildView v) {
 
-        // if the surface has exceed a predefined threshold then fix the size
-        // of the surface.
-        if (!v.isFixedSize && (v.width * v.height) > MAX_SURFACE_THRESHOLD
-                && v.mView instanceof SurfaceView) {
-            ((SurfaceView)v.mView).getHolder().setFixedSize(v.width, v.height);
-            v.isFixedSize = true;
-        }
+        int width = ctvD(v.width);
+        int height = ctvD(v.height);
+        int x = ctvX(v.x);
+        int y = ctvY(v.y);
 
         AbsoluteLayout.LayoutParams lp;
         ViewGroup.LayoutParams layoutParams = v.mView.getLayoutParams();
 
         if (layoutParams instanceof AbsoluteLayout.LayoutParams) {
             lp = (AbsoluteLayout.LayoutParams) layoutParams;
-            lp.width = ctvD(v.width);
-            lp.height = ctvD(v.height);
-            lp.x = ctvX(v.x);
-            lp.y = ctvY(v.y);
+            lp.width = width;
+            lp.height = height;
+            lp.x = x;
+            lp.y = y;
         } else {
-            lp = new AbsoluteLayout.LayoutParams(ctvD(v.width), ctvD(v.height),
-                    ctvX(v.x), ctvY(v.y));
+            lp = new AbsoluteLayout.LayoutParams(width, height, x, y);
         }
-        return lp;
+
+        // apply the layout to the view
+        v.mView.setLayoutParams(lp);
+
+        if(v.mView instanceof SurfaceView) {
+
+            final SurfaceView sView = (SurfaceView) v.mView;
+            boolean exceedThreshold = (width * height) > MAX_SURFACE_THRESHOLD;
+
+            /* If the surface has exceeded a predefined threshold or the webview
+             * is currently zoom then fix the size of the surface.
+             *
+             * NOTE: plugins (e.g. Flash) must not explicitly fix the size of
+             * their surface. The logic below will result in unexpected behavior
+             * for the plugin if they attempt to fix the size of the surface.
+             */
+            if (!sView.isFixedSize() && (exceedThreshold || mZoomInProgress)) {
+                sView.getHolder().setFixedSize(width, height);
+            }
+            else if (sView.isFixedSize() && !exceedThreshold && !mZoomInProgress) {
+                /* The changing of visibility is a hack to get around a bug in
+                 * the framework that causes the surface to revert to the size
+                 * it was prior to being fixed before it redraws using the
+                 * values currently in its layout.
+                 *
+                 * The surface is destroyed when it is set to invisible and then
+                 * recreated at the new dimensions when it is made visible. The
+                 * same destroy/create step occurs without the change in
+                 * visibility, but then exhibits the behavior described in the
+                 * previous paragraph.
+                 */
+                if (sView.getVisibility() == View.VISIBLE) {
+                    sView.setVisibility(View.INVISIBLE);
+                    sView.getHolder().setSizeFromLayout();
+                    sView.setVisibility(View.VISIBLE);
+                } else {
+                    sView.getHolder().setSizeFromLayout();
+                }
+            }
+            else if (sView.isFixedSize() && exceedThreshold) {
+                sView.requestLayout();
+            }
+        }
+    }
+
+    void startZoom() {
+        mZoomInProgress = true;
+        for (ChildView v : mChildren) {
+            requestLayout(v);
+        }
+    }
+
+    void endZoom() {
+        mZoomInProgress = false;
+        for (ChildView v : mChildren) {
+            requestLayout(v);
+        }
     }
 
     void scaleAll() {
         for (ChildView v : mChildren) {
-            v.mView.setLayoutParams(computeLayout(v));
+            requestLayout(v);
         }
     }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index cabda85..f886eef 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,
@@ -4192,7 +4195,15 @@
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
-        sendOurVisibleRect();
+        if (!mInOverScrollMode) {
+            sendOurVisibleRect();
+            // update WebKit if visible title bar height changed. The logic is same
+            // as getVisibleTitleHeight.
+            int titleHeight = getTitleHeight();
+            if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
+                sendViewSizeZoom();
+            }
+        }
     }
 
     @Override
@@ -4449,6 +4460,9 @@
             if (inEditingMode() && nativeFocusCandidateIsPassword()) {
                 mWebTextView.setInPassword(false);
             }
+
+            mViewManager.startZoom();
+
             return true;
         }
 
@@ -4482,6 +4496,8 @@
             mConfirmMove = true;
             startTouch(detector.getFocusX(), detector.getFocusY(),
                     mLastTouchTime);
+
+            mViewManager.endZoom();
         }
 
         public boolean onScale(ScaleGestureDetector detector) {
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..9150b5e 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;
@@ -2599,8 +2601,9 @@
         }
 
         void startOverfling(int initialVelocity) {
-            mScroller.fling(0, mScrollY, 0, initialVelocity, 0, 0, 0, 0, 0, getHeight());
-            edgeReached();
+            final int min = mScrollY > 0 ? Integer.MIN_VALUE : 0;
+            final int max = mScrollY > 0 ? 0 : Integer.MAX_VALUE;
+            mScroller.fling(0, mScrollY, 0, initialVelocity, 0, 0, min, max, 0, getHeight());
             mTouchMode = TOUCH_MODE_OVERFLING;
             invalidate();
             post(this);
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 6258024..48e7493 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -42,11 +42,31 @@
     }
 
     /**
-     * Creates a Scroller with the specified interpolator. If the interpolator is
-     * null, the default (viscous) interpolator will be used.
+     * Creates an OverScroller with default edge bounce coefficients.
+     * @param context The context of this application.
+     * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+     * be used.
      */
     public OverScroller(Context context, Interpolator interpolator) {
+        this(context, interpolator, MagneticOverScroller.DEFAULT_BOUNCE_COEFFICIENT,
+                MagneticOverScroller.DEFAULT_BOUNCE_COEFFICIENT);
+    }
+
+    /**
+     * Creates an OverScroller.
+     * @param context The context of this application.
+     * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+     * be used.
+     * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the
+     * velocity which is preserved in the bounce when the horizontal edge is reached. A null value
+     * means no bounce.
+     * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction.
+     */
+    public OverScroller(Context context, Interpolator interpolator,
+            float bounceCoefficientX, float bounceCoefficientY) {
         super(context, interpolator);
+        mOverScrollerX.setBounceCoefficient(bounceCoefficientX);
+        mOverScrollerY.setBounceCoefficient(bounceCoefficientY);
     }
 
     @Override
@@ -69,8 +89,11 @@
      */
     public boolean springback(int startX, int startY, int minX, int maxX, int minY, int maxY) {
         mMode = FLING_MODE;
-        return mOverScrollerX.springback(startX, minX, maxX)
-                || mOverScrollerY.springback(startY, minY, maxY);
+
+        // Make sure both methods are called.
+        final boolean spingbackX = mOverScrollerX.springback(startX, minX, maxX);
+        final boolean spingbackY = mOverScrollerY.springback(startY, minY, maxY);
+        return spingbackX || spingbackY;
     }
 
     @Override
@@ -130,8 +153,8 @@
     }
 
     /**
-     * Returns whether the current Scroller position is overscrolled or still within the minimum and
-     * maximum bounds provided in the
+     * Returns whether the current Scroller is currently returning to a valid position.
+     * Valid bounds were provided by the
      * {@link #fling(int, int, int, int, int, int, int, int, int, int)} method.
      * 
      * One should check this value before calling
@@ -139,11 +162,13 @@
      * a valid position will then be stopped. The caller has to take into account the fact that the
      * started scroll will start from an overscrolled position.
      * 
-     * @return true when the current position is overscrolled.
+     * @return true when the current position is overscrolled and interpolated back to a valid value.
      */
     public boolean isOverscrolled() {
-        return ((!mOverScrollerX.mFinished && mOverScrollerX.mState != MagneticOverScroller.TO_EDGE) ||
-                (!mOverScrollerY.mFinished && mOverScrollerY.mState != MagneticOverScroller.TO_EDGE));
+        return ((!mOverScrollerX.mFinished &&
+                mOverScrollerX.mState != MagneticOverScroller.TO_EDGE) ||
+                (!mOverScrollerY.mFinished &&
+                        mOverScrollerY.mState != MagneticOverScroller.TO_EDGE));
     }
 
     static class MagneticOverScroller extends Scroller.MagneticScroller {
@@ -156,30 +181,25 @@
         // The allowed overshot distance before boundary is reached.
         private int mOver;
 
-        // When the scroll goes beyond the edges limits, the deceleration is
-        // multiplied by this coefficient, so that the return to a valid
-        // position is faster.
-        private static final float OVERSCROLL_DECELERATION_COEF = 16.0f;
+        // Duration in milliseconds to go back from edge to edge. Springback is half of it.
+        private static final int OVERSCROLL_SPRINGBACK_DURATION = 200;
+
+        // Oscillation period
+        private static final float TIME_COEF =
+            1000.0f * (float) Math.PI / OVERSCROLL_SPRINGBACK_DURATION;
 
         // If the velocity is smaller than this value, no bounce is triggered
         // when the edge limits are reached (would result in a zero pixels
         // displacement anyway).
-        private static final float MINIMUM_VELOCITY_FOR_BOUNCE = 200.0f;
+        private static final float MINIMUM_VELOCITY_FOR_BOUNCE = 140.0f;
 
-        // Could be made public for tuning, but applications would no longer
-        // have the same look and feel.
-        private static final float BOUNCE_COEFFICIENT = 0.4f;
+        // Proportion of the velocity that is preserved when the edge is reached.
+        private static final float DEFAULT_BOUNCE_COEFFICIENT = 0.16f;
 
-        /*
-         * Get a signed deceleration that will reduce the velocity.
-         */
-        @Override
-        float getDeceleration(int velocity) {
-            float decelerationY = super.getDeceleration(velocity);
-            if (mState != TO_EDGE) {
-                decelerationY *= OVERSCROLL_DECELERATION_COEF;
-            }
-            return decelerationY;
+        private float mBounceCoefficient = DEFAULT_BOUNCE_COEFFICIENT;
+
+        void setBounceCoefficient(float coefficient) {
+            mBounceCoefficient = coefficient;
         }
 
         boolean springback(int start, int min, int max) {
@@ -192,20 +212,21 @@
             mDuration = 0;
 
             if (start < min) {
-                startSpringback(start, min, -1);
+                startSpringback(start, min, false);
             } else if (start > max) {
-                startSpringback(start, max, 1);
+                startSpringback(start, max, true);
             }
 
             return !mFinished;
         }
 
-        private void startSpringback(int start, int end, int sign) {
+        private void startSpringback(int start, int end, boolean positive) {
             mFinished = false;
             mState = TO_BOUNCE;
-            mDeceleration = getDeceleration(sign);
-            mFinal = end;
-            mDuration = (int) (1000.0f * Math.sqrt(2.0f * (end - start) / mDeceleration));
+            mStart = mFinal = end;
+            mDuration = OVERSCROLL_SPRINGBACK_DURATION;
+            mStartTime -= OVERSCROLL_SPRINGBACK_DURATION / 2;
+            mVelocity = (int) (Math.abs(end - start) * TIME_COEF * (positive ? 1.0 : -1.0f));
         }
 
         void fling(int start, int velocity, int min, int max, int over) {
@@ -214,39 +235,60 @@
 
             super.fling(start, velocity, min, max);
 
-            if (mStart > max) {
-                if (mStart >= max + over) {
+            if (start > max) {
+                if (start >= max + over) {
                     springback(max + over, min, max);
                 } else {
-                    // Make sure the deceleration brings us back to edge
-                    mVelocity = velocity > 0 ? velocity : -velocity;
-                    mCurrVelocity = velocity;
-                    notifyEdgeReached(start, max, over);
+                    if (velocity <= 0) {
+                        springback(start, min, max);
+                    } else {
+                        long time = AnimationUtils.currentAnimationTimeMillis();
+                        final double durationSinceEdge =
+                            Math.atan((start-max) * TIME_COEF / velocity) / TIME_COEF;
+                        mStartTime = (int) (time - 1000.0f * durationSinceEdge);
+
+                        // Simulate a bounce that started from edge
+                        mStart = max;
+
+                        mVelocity = (int) (velocity / Math.cos(durationSinceEdge * TIME_COEF));
+
+                        onEdgeReached();
+                    }
                 }
             } else {
-                if (mStart < min) {
-                    if (mStart <= min - over) {
+                if (start < min) {
+                    if (start <= min - over) {
                         springback(min - over, min, max);
                     } else {
-                        // Make sure the deceleration brings us back to edge
-                        mVelocity = velocity < 0 ? velocity : -velocity;
-                        mCurrVelocity = velocity;
-                        notifyEdgeReached(start, min, over);
+                        if (velocity >= 0) {
+                            springback(start, min, max);
+                        } else {
+                            long time = AnimationUtils.currentAnimationTimeMillis();
+                            final double durationSinceEdge =
+                                Math.atan((start-min) * TIME_COEF / velocity) / TIME_COEF;
+                            mStartTime = (int) (time - 1000.0f * durationSinceEdge);
+
+                            // Simulate a bounce that started from edge
+                            mStart = min;
+
+                            mVelocity = (int) (velocity / Math.cos(durationSinceEdge * TIME_COEF));
+
+                            onEdgeReached();
+                        }
+
                     }
                 }
             }
         }
 
         void notifyEdgeReached(int start, int end, int over) {
-            // Compute post-edge deceleration
-            mState = TO_BOUNDARY;
             mDeceleration = getDeceleration(mVelocity);
 
             // Local time, used to compute edge crossing time.
             float timeCurrent = mCurrVelocity / mDeceleration;
             final int distance = end - start;
             float timeEdge = -(float) Math.sqrt((2.0f * distance / mDeceleration)
-                             + (timeCurrent * timeCurrent));
+                    + (timeCurrent * timeCurrent));
 
             mVelocity = (int) (mDeceleration * timeEdge);
 
@@ -261,22 +303,21 @@
             onEdgeReached();
         }
 
-        void onEdgeReached() {
+        private void onEdgeReached() {
             // mStart, mVelocity and mStartTime were adjusted to their values when edge was reached.
-            mState = TO_BOUNDARY;
-            mDeceleration = getDeceleration(mVelocity);
-
-            int distance = Math.round((mVelocity * mVelocity) / (2.0f * mDeceleration));
+            final float distance = mVelocity / TIME_COEF;
 
             if (Math.abs(distance) < mOver) {
-                // Deceleration will bring us back to final position
+                // Spring force will bring us back to final position
                 mState = TO_BOUNCE;
                 mFinal = mStart;
-                mDuration = (int) (-2000.0f * mVelocity / mDeceleration);
+                mDuration = OVERSCROLL_SPRINGBACK_DURATION;
             } else {
                 // Velocity is too high, we will hit the boundary limit
-                mFinal = mStart + (mVelocity > 0 ? mOver : -mOver);
-                mDuration = computeDuration(mStart, mFinal, mVelocity, mDeceleration);
+                mState = TO_BOUNDARY;
+                int over = mVelocity > 0 ? mOver : -mOver;
+                mFinal = mStart + over;
+                mDuration = (int) (1000.0f * Math.asin(over / distance) / TIME_COEF);
             }
         }
 
@@ -300,26 +341,49 @@
                     break;
                 case TO_BOUNDARY:
                     mStartTime += mDuration;
-                    mStart = mFinal;
-                    mFinal = mStart - (mVelocity > 0 ? mOver : -mOver);
-                    mVelocity = 0;
-                    mDuration = (int) (1000.0f * Math.sqrt(Math.abs(2.0f * mOver / mDeceleration)));
-                    mState = TO_BOUNCE;
+                    startSpringback(mFinal, mFinal - (mVelocity > 0 ? mOver:-mOver), mVelocity > 0);
                     break;
                 case TO_BOUNCE:
-                    float edgeVelocity = mVelocity + mDeceleration * mDuration / 1000.0f;
-                    mVelocity = (int) (-edgeVelocity * BOUNCE_COEFFICIENT);
+                    //mVelocity = (int) (mVelocity * BOUNCE_COEFFICIENT);
+                    mVelocity = (int) (mVelocity * mBounceCoefficient);
                     if (Math.abs(mVelocity) < MINIMUM_VELOCITY_FOR_BOUNCE) {
                         return false;
                     }
-                    mStart = mFinal;
                     mStartTime += mDuration;
-                    mDuration = (int) (-2000.0f * mVelocity / mDeceleration);
                     break;
             }
 
             update();
             return true;
         }
+
+        /*
+         * Update the current position and velocity for current time. Returns
+         * true if update has been done and false if animation duration has been
+         * reached.
+         */
+        @Override
+        boolean update() {
+            final long time = AnimationUtils.currentAnimationTimeMillis();
+            final long duration = time - mStartTime;
+
+            if (duration > mDuration) {
+                return false;
+            }
+
+            double distance;
+            final float t = duration / 1000.0f;
+            if (mState == TO_EDGE) {
+                mCurrVelocity = mVelocity + mDeceleration * t;
+                distance = mVelocity * t + mDeceleration * t * t / 2.0f;
+            } else {
+                final float d = t * TIME_COEF;
+                mCurrVelocity = mVelocity * (float)Math.cos(d);
+                distance = mVelocity / TIME_COEF * Math.sin(d);
+            }
+
+            mCurrentPosition = mStart + (int) distance;
+            return true;
+        }
     }
 }
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 542866a..6a2f000 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -431,7 +431,7 @@
         /*
          * Get a signed deceleration that will reduce the velocity.
          */
-        float getDeceleration(int velocity) {
+        static float getDeceleration(int velocity) {
             return velocity > 0 ? -GRAVITY : GRAVITY;
         }
 
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 479965a..4b17a92 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -172,6 +172,10 @@
                     if (v instanceof Checkable) {
                         if (data instanceof Boolean) {
                             ((Checkable) v).setChecked((Boolean) data);
+                        } else if (v instanceof TextView) {
+                            // Note: keep the instanceof TextView check at the bottom of these
+                            // ifs since a lot of views are TextViews (e.g. CheckBoxes).
+                            setViewText((TextView) v, text);
                         } else {
                             throw new IllegalStateException(v.getClass().getName() +
                                     " should be bound to a Boolean, not a " +
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index ea99f03..52a560c 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -221,7 +221,7 @@
      * @param drawable the right strip drawable
      */
     public void setRightStripDrawable(Drawable drawable) {
-        mBottomLeftStrip = drawable;
+        mBottomRightStrip = drawable;
         requestLayout();
         invalidate();    }
 
@@ -232,7 +232,7 @@
      * 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/res/values/themes.xml b/core/res/res/values/themes.xml
index 9e19c57..6dae8b8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -471,7 +471,6 @@
 
     <!-- Theme for the search input bar. -->
     <style name="Theme.SearchBar" parent="Theme.Panel">
-        <item name="android:backgroundDimEnabled">true</item>
         <item name="windowContentOverlay">@null</item>        
     </style>
     
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/data/fonts/DroidSansHebrew.ttf b/data/fonts/DroidSansHebrew.ttf
index 8cc670d..0b48628 100644
--- a/data/fonts/DroidSansHebrew.ttf
+++ b/data/fonts/DroidSansHebrew.ttf
Binary files differ
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 44a5a6b..8dc206c 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -35,8 +35,12 @@
 import android.net.NetworkInfo;
 import android.net.SntpClient;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -65,13 +69,13 @@
  *
  * {@hide}
  */
-public class GpsLocationProvider implements LocationProviderInterface {
+public class GpsLocationProvider implements LocationProviderInterface, Runnable {
 
     private static final String TAG = "GpsLocationProvider";
 
     private static final boolean DEBUG = false;
     private static final boolean VERBOSE = false;
-    
+
     /**
      * Broadcast intent action indicating that the GPS has either been
      * enabled or disabled. An intent extra provides this state as a boolean,
@@ -155,6 +159,17 @@
     private static final int AGPS_DATA_CONNECTION_OPENING = 1;
     private static final int AGPS_DATA_CONNECTION_OPEN = 2;
 
+    // Handler messages
+    private static final int CHECK_LOCATION = 1;
+    private static final int ENABLE = 2;
+    private static final int ENABLE_TRACKING = 3;
+    private static final int UPDATE_NETWORK_STATE = 4;
+    private static final int INJECT_NTP_TIME = 5;
+    private static final int DOWNLOAD_XTRA_DATA = 6;
+    private static final int UPDATE_LOCATION = 7;
+    private static final int ADD_LISTENER = 8;
+    private static final int REMOVE_LISTENER = 9;
+
     private static final String PROPERTIES_FILE = "/etc/gps.conf";
 
     private int mLocationFlags = LOCATION_INVALID;
@@ -180,6 +195,11 @@
     // true if we have network connectivity
     private boolean mNetworkAvailable;
 
+    // flags to trigger NTP or XTRA data download when network becomes available
+    // initialized to true so we do NTP and XTRA when the network comes up after booting
+    private boolean mInjectNtpTimePending = true;
+    private boolean mDownloadXtraDataPending = true;
+
     // true if GPS is navigating
     private boolean mNavigating;
 
@@ -215,9 +235,9 @@
     private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
     private Bundle mLocationExtras = new Bundle();
     private ArrayList<Listener> mListeners = new ArrayList<Listener>();
-    private GpsEventThread mEventThread;
-    private GpsNetworkThread mNetworkThread;
-    private Object mNetworkThreadLock = new Object();
+
+    private Handler mHandler;
+    private Thread mEventThread;
 
     private String mAGpsApn;
     private int mAGpsDataConnectionState;
@@ -333,11 +353,6 @@
         mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
         mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
 
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ALARM_WAKEUP);
-        intentFilter.addAction(ALARM_TIMEOUT);
-        context.registerReceiver(mBroadcastReciever, intentFilter);
-
         mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
 
         // Battery statistics service to be notified when GPS turns on or off
@@ -373,6 +388,17 @@
         } catch (IOException e) {
             Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
         }
+
+        Thread thread = new Thread(null, this, "GpsLocationProvider");
+        thread.start();
+    }
+
+    private void initialize() {
+        // register our receiver on our thread rather than the main thread
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ALARM_WAKEUP);
+        intentFilter.addAction(ALARM_TIMEOUT);
+        mContext.registerReceiver(mBroadcastReciever, intentFilter);
     }
 
     /**
@@ -391,6 +417,14 @@
     }
 
     public void updateNetworkState(int state, NetworkInfo info) {
+        mHandler.removeMessages(UPDATE_NETWORK_STATE);
+        Message m = Message.obtain(mHandler, UPDATE_NETWORK_STATE);
+        m.arg1 = state;
+        m.obj = info;
+        mHandler.sendMessage(m);
+    }
+
+    private void handleUpdateNetworkState(int state, NetworkInfo info) {
         mNetworkAvailable = (state == LocationProvider.AVAILABLE);
 
         if (DEBUG) {
@@ -414,10 +448,84 @@
             }
         }
 
-        if (mNetworkAvailable && mNetworkThread != null && mEnabled) {
-            // signal the network thread when the network becomes available
-            mNetworkThread.signal();
-        } 
+        if (mNetworkAvailable) {
+            if (mInjectNtpTimePending) {
+                mHandler.removeMessages(INJECT_NTP_TIME);
+                mHandler.sendMessage(Message.obtain(mHandler, INJECT_NTP_TIME));
+            }
+            if (mDownloadXtraDataPending) {
+                mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
+                mHandler.sendMessage(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA));
+            }
+        }
+    }
+
+    private void handleInjectNtpTime() {
+        if (!mNetworkAvailable) {
+            // try again when network is up
+            mInjectNtpTimePending = true;
+            return;
+        }
+        mInjectNtpTimePending = false;
+
+        SntpClient client = new SntpClient();
+        long delay;
+
+        if (client.requestTime(mNtpServer, 10000)) {
+            long time = client.getNtpTime();
+            long timeReference = client.getNtpTimeReference();
+            int certainty = (int)(client.getRoundTripTime()/2);
+            long now = System.currentTimeMillis();
+            long systemTimeOffset = time - now;
+
+            Log.d(TAG, "NTP server returned: "
+                    + time + " (" + new Date(time)
+                    + ") reference: " + timeReference
+                    + " certainty: " + certainty
+                    + " system time offset: " + systemTimeOffset);
+
+            // sanity check NTP time and do not use if it is too far from system time
+            if (systemTimeOffset < 0) {
+                systemTimeOffset = -systemTimeOffset;
+            }
+            if (systemTimeOffset < MAX_NTP_SYSTEM_TIME_OFFSET) {
+                native_inject_time(time, timeReference, certainty);
+            } else {
+                Log.e(TAG, "NTP time differs from system time by " + systemTimeOffset
+                        + "ms.  Ignoring.");
+            }
+            delay = NTP_INTERVAL;
+        } else {
+            if (DEBUG) Log.d(TAG, "requestTime failed");
+            delay = RETRY_INTERVAL;
+        }
+
+        // send delayed message for next NTP injection
+        mHandler.removeMessages(INJECT_NTP_TIME);
+        mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+    }
+
+    private void handleDownloadXtraData() {
+        if (!mDownloadXtraDataPending) {
+            // try again when network is up
+            mDownloadXtraDataPending = true;
+            return;
+        }
+        mDownloadXtraDataPending = false;
+
+
+        GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
+        byte[] data = xtraDownloader.downloadXtraData();
+        if (data != null) {
+            if (DEBUG) {
+                Log.d(TAG, "calling native_inject_xtra_data");
+            }
+            native_inject_xtra_data(data, data.length);
+        } else {
+            // try again later
+            mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
+            mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA), RETRY_INTERVAL);
+        }
     }
 
     /**
@@ -425,6 +533,13 @@
      * Someday we might use this for network location injection to aid the GPS
      */
     public void updateLocation(Location location) {
+        mHandler.removeMessages(UPDATE_LOCATION);
+        Message m = Message.obtain(mHandler, UPDATE_LOCATION);
+        m.obj = location;
+        mHandler.sendMessage(m);
+    }
+
+    private void handleUpdateLocation(Location location) {
         if (location.hasAccuracy()) {
             native_inject_location(location.getLatitude(), location.getLongitude(),
                     location.getAccuracy());
@@ -513,8 +628,17 @@
      * must be handled.  Hardware may be started up
      * when the provider is enabled.
      */
-    public synchronized void enable() {
-        if (DEBUG) Log.d(TAG, "enable");
+    public void enable() {
+        synchronized (mHandler) {
+            mHandler.removeMessages(ENABLE);
+            Message m = Message.obtain(mHandler, ENABLE);
+            m.arg1 = 1;
+            mHandler.sendMessage(m);
+        }
+    }
+
+    private void handleEnable() {
+        if (DEBUG) Log.d(TAG, "handleEnable");
         if (mEnabled) return;
         mEnabled = native_init();
 
@@ -529,16 +653,6 @@
             // run event listener thread while we are enabled
             mEventThread = new GpsEventThread();
             mEventThread.start();
-
-            if (requiresNetwork()) {
-                // run network thread for NTP and XTRA support
-                if (mNetworkThread == null) {
-                    mNetworkThread = new GpsNetworkThread();
-                    mNetworkThread.start();
-                } else {
-                    mNetworkThread.signal();
-                }
-            }
         } else {
             Log.w(TAG, "Failed to enable location provider");
         }
@@ -549,8 +663,17 @@
      * need not be handled.  Hardware may be shut
      * down while the provider is disabled.
      */
-    public synchronized void disable() {
-        if (DEBUG) Log.d(TAG, "disable");
+    public void disable() {
+        synchronized (mHandler) {
+            mHandler.removeMessages(ENABLE);
+            Message m = Message.obtain(mHandler, ENABLE);
+            m.arg1 = 0;
+            mHandler.sendMessage(m);
+        }
+    }
+
+    private void handleDisable() {
+        if (DEBUG) Log.d(TAG, "handleEnable");
         if (!mEnabled) return;
 
         mEnabled = false;
@@ -567,11 +690,6 @@
             mEventThread = null;
         }
 
-        if (mNetworkThread != null) {
-            mNetworkThread.setDone();
-            mNetworkThread = null;
-        }
-
         // do this before releasing wakelock
         native_cleanup();
 
@@ -610,6 +728,15 @@
     }
 
     public void enableLocationTracking(boolean enable) {
+        synchronized (mHandler) {
+            mHandler.removeMessages(ENABLE_TRACKING);
+            Message m = Message.obtain(mHandler, ENABLE_TRACKING);
+            m.arg1 = (enable ? 1 : 0);
+            mHandler.sendMessage(m);
+        }
+    }
+
+    private void handleEnableLocationTracking(boolean enable) {
         if (enable) {
             mTTFF = 0;
             mLastFixTime = 0;
@@ -659,6 +786,12 @@
     }
 
     public void addListener(int uid) {
+        Message m = Message.obtain(mHandler, ADD_LISTENER);
+        m.arg1 = uid;
+        mHandler.sendMessage(m);
+    }
+
+    private void handleAddListener(int uid) {
         synchronized(mListeners) {
             if (mClientUids.indexOfKey(uid) >= 0) {
                 // Shouldn't be here -- already have this uid.
@@ -677,6 +810,12 @@
     }
 
     public void removeListener(int uid) {
+        Message m = Message.obtain(mHandler, REMOVE_LISTENER);
+        m.arg1 = uid;
+        mHandler.sendMessage(m);
+    }
+
+    private void handleRemoveListener(int uid) {
         synchronized(mListeners) {
             if (mClientUids.indexOfKey(uid) < 0) {
                 // Shouldn't be here -- don't have this uid.
@@ -700,10 +839,12 @@
             return deleteAidingData(extras);
         }
         if ("force_time_injection".equals(command)) {
-            return forceTimeInjection();
+            mHandler.removeMessages(INJECT_NTP_TIME);
+            mHandler.sendMessage(Message.obtain(mHandler, INJECT_NTP_TIME));
+            return true;
         }
         if ("force_xtra_injection".equals(command)) {
-            if (native_supports_xtra() && mNetworkThread != null) {
+            if (native_supports_xtra()) {
                 xtraDownloadRequest();
                 return true;
             }
@@ -744,16 +885,7 @@
         return false;
     }
 
-    private boolean forceTimeInjection() {
-        if (DEBUG) Log.d(TAG, "forceTimeInjection");
-        if (mNetworkThread != null) {
-            mNetworkThread.timeInjectRequest();
-            return true;
-        }
-        return false;
-    }
-
-    public void startNavigating() {
+    private void startNavigating() {
         if (!mStarted) {
             if (DEBUG) Log.d(TAG, "startNavigating");
             mStarted = true;
@@ -784,7 +916,7 @@
         }
     }
 
-    public void stopNavigating() {
+    private void stopNavigating() {
         if (DEBUG) Log.d(TAG, "stopNavigating");
         if (mStarted) {
             mStarted = false;
@@ -1092,11 +1224,13 @@
         }
     }
 
+    /**
+     * called from native code to request XTRA data
+     */
     private void xtraDownloadRequest() {
         if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
-        if (mNetworkThread != null) {
-            mNetworkThread.xtraDownloadRequest();
-        }
+        mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
+        mHandler.sendMessage(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA));
     }
 
     //=============================================================
@@ -1189,6 +1323,10 @@
 		mNIHandler.handleNiNotification(notification);		
 	}
 
+    // this thread is used to receive events from the native code.
+    // native_wait_for_event() will callback to us via reportLocation(), reportStatus(), etc.
+    // this is necessary because native code cannot call Java on a thread that the JVM does
+    // not know about.
     private class GpsEventThread extends Thread {
 
         public GpsEventThread() {
@@ -1207,157 +1345,52 @@
         }
     }
 
-    private class GpsNetworkThread extends Thread {
-
-        private long mNextNtpTime = 0;
-        private long mNextXtraTime = 0;
-        private boolean mTimeInjectRequested = false;
-        private boolean mXtraDownloadRequested = false;
-        private boolean mDone = false;
-
-        public GpsNetworkThread() {
-            super("GpsNetworkThread");
-        }
-
-        public void run() {
-            synchronized (mNetworkThreadLock) {
-                if (!mDone) {
-                    runLocked();
-                }
-            }
-        }
-
-        public void runLocked() {
-            if (DEBUG) Log.d(TAG, "NetworkThread starting");
-            
-            SntpClient client = new SntpClient();
-            GpsXtraDownloader xtraDownloader = null;
-            
-            if (native_supports_xtra()) {
-                xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
-            }
-            
-            // thread exits after disable() is called
-            while (!mDone) {
-                long waitTime = getWaitTime();
-                do {                        
-                    synchronized (this) {
-                        try {
-                            if (!mNetworkAvailable) {
-                                if (DEBUG) Log.d(TAG, "NetworkThread wait for network");
-                                wait();
-                            } else if (waitTime > 0) {
-                                if (DEBUG) {
-                                    Log.d(TAG, "NetworkThread wait for " +
-                                            waitTime + "ms");
-                                }
-                                wait(waitTime);
-                            }
-                        } catch (InterruptedException e) {
-                            if (DEBUG) {
-                                Log.d(TAG, "InterruptedException in GpsNetworkThread");
-                            }
-                        }
+    private final class ProviderHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg)
+        {
+            switch (msg.what) {
+                case ENABLE:
+                    if (msg.arg1 == 1) {
+                        handleEnable();
+                    } else {
+                        handleDisable();
                     }
-                    waitTime = getWaitTime();
-                } while (!mDone && ((!mXtraDownloadRequested &&
-                        !mTimeInjectRequested && waitTime > 0)
-                        || !mNetworkAvailable));
-                if (DEBUG) Log.d(TAG, "NetworkThread out of wake loop"); 
-                if (!mDone) {
-                    if (mNtpServer != null && 
-                            (mTimeInjectRequested || mNextNtpTime <= System.currentTimeMillis())) {
-                        if (DEBUG) {
-                            Log.d(TAG, "Requesting time from NTP server " + mNtpServer);
-                        }
-                        mTimeInjectRequested = false;
-                        if (client.requestTime(mNtpServer, 10000)) {
-                            long time = client.getNtpTime();
-                            long timeReference = client.getNtpTimeReference();
-                            int certainty = (int)(client.getRoundTripTime()/2);
-                            long now = System.currentTimeMillis();
-                            long systemTimeOffset = time - now;
-        
-                            Log.d(TAG, "NTP server returned: "
-                                    + time + " (" + new Date(time)
-                                    + ") reference: " + timeReference
-                                    + " certainty: " + certainty
-                                    + " system time offset: " + systemTimeOffset);
-
-                            // sanity check NTP time and do not use if it is too far from system time
-                            if (systemTimeOffset < 0) {
-                                systemTimeOffset = -systemTimeOffset;
-                            }
-                            if (systemTimeOffset < MAX_NTP_SYSTEM_TIME_OFFSET) {
-                                native_inject_time(time, timeReference, certainty);
-                            } else {
-                                Log.e(TAG, "NTP time differs from system time by " + systemTimeOffset
-                                        + "ms.  Ignoring.");
-                            }
-                            mNextNtpTime = now + NTP_INTERVAL;
-                        } else {
-                            if (DEBUG) Log.d(TAG, "requestTime failed");
-                            mNextNtpTime = System.currentTimeMillis() + RETRY_INTERVAL;
-                        }
+                    break;
+                case ENABLE_TRACKING:
+                    handleEnableLocationTracking(msg.arg1 == 1);
+                    break;
+                case UPDATE_NETWORK_STATE:
+                    handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
+                    break;
+                case INJECT_NTP_TIME:
+                    handleInjectNtpTime();
+                    break;
+                case DOWNLOAD_XTRA_DATA:
+                    if (native_supports_xtra()) {
+                        handleDownloadXtraData();
                     }
-
-                    if ((mXtraDownloadRequested || 
-                            (mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis()))
-                            && xtraDownloader != null) {
-                        mXtraDownloadRequested = false;
-                        byte[] data = xtraDownloader.downloadXtraData();
-                        if (data != null) {
-                            if (DEBUG) {
-                                Log.d(TAG, "calling native_inject_xtra_data");
-                            }
-                            native_inject_xtra_data(data, data.length);
-                            mNextXtraTime = 0;
-                        } else {
-                            mNextXtraTime = System.currentTimeMillis() + RETRY_INTERVAL;
-                        }
-                    }
-                }
+                    break;
+                case UPDATE_LOCATION:
+                    handleUpdateLocation((Location)msg.obj);
+                    break;
+                case ADD_LISTENER:
+                    handleAddListener(msg.arg1);
+                    break;
+                case REMOVE_LISTENER:
+                    handleRemoveListener(msg.arg1);
+                    break;
             }
-            if (DEBUG) Log.d(TAG, "NetworkThread exiting");
         }
-        
-        synchronized void xtraDownloadRequest() {
-            mXtraDownloadRequested = true;
-            notify();
-        }
+    };
 
-        synchronized void timeInjectRequest() {
-            mTimeInjectRequested = true;
-            notify();
-        }
-
-        synchronized void signal() {
-            notify();
-        }
-
-        synchronized void setDone() {
-            if (DEBUG) Log.d(TAG, "stopping NetworkThread");
-            mDone = true;
-            notify();
-        }
-
-        private long getWaitTime() {
-            long now = System.currentTimeMillis();
-            long waitTime = Long.MAX_VALUE;
-            if (mNtpServer != null) {
-                waitTime = mNextNtpTime - now;
-            }
-            if (mNextXtraTime != 0) {
-                long xtraWaitTime = mNextXtraTime - now;
-                if (xtraWaitTime < waitTime) {
-                    waitTime = xtraWaitTime;
-                }
-            }
-            if (waitTime < 0) {
-                waitTime = 0;
-            }
-            return waitTime;
-        }
+    public void run()
+    {
+        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+        initialize();
+        Looper.prepare();
+        mHandler = new ProviderHandler();
+        Looper.loop();
     }
 
     // for GPS SV statistics
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/MountService.java b/services/java/com/android/server/MountService.java
index d3ac026..10920fa 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -100,6 +100,7 @@
         public static final int OpFailedMediaCorrupt           = 403;
         public static final int OpFailedVolNotMounted          = 404;
         public static final int OpFailedStorageBusy            = 405;
+        public static final int OpFailedStorageNotFound        = 406;
 
         /*
          * 600 series - Unsolicited broadcasts.
@@ -1203,7 +1204,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) {
@@ -1287,21 +1291,22 @@
         waitForReady();
         warnOnNotMounted();
 
-        ArrayList<String> rsp = mConnector.doCommand("asec path " + id);
-
-        for (String line : rsp) {
-            String []tok = line.split(" ");
+        try {
+            ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id));
+            String []tok = rsp.get(0).split(" ");
             int code = Integer.parseInt(tok[0]);
-            if (code == VoldResponseCode.AsecPathResult) {
-                return tok[1];
+            if (code != VoldResponseCode.AsecPathResult) {
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+            }
+            return tok[1];
+        } catch (NativeDaemonConnectorException e) {
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedStorageNotFound) {
+                throw new IllegalArgumentException(String.format("Container '%s' not found", id));
             } else {
-                Log.e(TAG, String.format("Unexpected response code %d", code));
-                return "";
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
             }
         }
-
-        Log.e(TAG, "Got an empty response");
-        return "";
     }
 
     public void finishMediaUpdate() {
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 39c847a..08d7ce6 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -48,6 +48,8 @@
     private String                mSocket;
     private INativeDaemonConnectorCallbacks mCallbacks;
 
+    private final int BUFFER_SIZE = 4096;
+
     class ResponseCode {
         public static final int ActionInitiated                = 100;
 
@@ -87,7 +89,7 @@
     }
 
     private void listenToSocket() throws IOException {
-       LocalSocket socket = null;
+        LocalSocket socket = null;
 
         try {
             socket = new LocalSocket();
@@ -100,13 +102,13 @@
             InputStream inputStream = socket.getInputStream();
             mOutputStream = socket.getOutputStream();
 
-            byte[] buffer = new byte[4096];
+            byte[] buffer = new byte[BUFFER_SIZE];
+            int start = 0;
 
             while (true) {
-                int count = inputStream.read(buffer);
+                int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
                 if (count < 0) break;
 
-                int start = 0;
                 for (int i = 0; i < count; i++) {
                     if (buffer[i] == 0) {
                         String event = new String(buffer, start, i - start);
@@ -139,6 +141,13 @@
                         start = i + 1;
                     }
                 }
+                if (start != count) {
+                    final int remaining = BUFFER_SIZE - start;
+                    System.arraycopy(buffer, start, buffer, 0, remaining);
+                    start = remaining;
+                } else {
+                    start = 0;
+                }
             }
         } catch (IOException ex) {
             Slog.e(TAG, "Communications error", ex);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 9eb63a6..53415c7 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3977,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
@@ -3989,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;
                                 }
@@ -4001,6 +4001,8 @@
                             changedPermission = true;
                             gp.grantedPermissions.add(perm);
                             gp.gids = appendInts(gp.gids, bp.gids);
+                        } else if (!ps.haveGids) {
+                            gp.gids = appendInts(gp.gids, bp.gids);
                         }
                     } else {
                         Slog.w(TAG, "Not granting permission " + perm
@@ -4037,8 +4039,8 @@
             // permissions we have now selected are fixed until explicitly
             // changed.
             ps.permissionsFixed = true;
-            gp.loadedPermissions = new HashSet<String>(gp.grantedPermissions);
         }
+        ps.haveGids = true;
     }
     
     private final class ActivityIntentResolver
@@ -6927,7 +6929,8 @@
                     pw.print("    timeStamp="); pw.println(ps.getTimeStampStr());
                     pw.print("    signatures="); pw.println(ps.signatures);
                     pw.print("    permissionsFixed="); pw.print(ps.permissionsFixed);
-                            pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
+                            pw.print(" haveGids="); pw.println(ps.haveGids);
+                    pw.print("    pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
                             pw.print(" installStatus="); pw.print(ps.installStatus);
                             pw.print(" enabled="); pw.println(ps.enabled);
                     if (ps.disabledComponents.size() > 0) {
@@ -6948,12 +6951,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;
@@ -7022,10 +7019,6 @@
                     for (String s : su.grantedPermissions) {
                         pw.print("      "); pw.println(s);
                     }
-                    pw.println("    loadedPermissions:");
-                    for (String s : su.loadedPermissions) {
-                        pw.print("      "); pw.println(s);
-                    }
                 }
             }
             
@@ -7528,8 +7521,6 @@
         HashSet<String> grantedPermissions = new HashSet<String>();
         int[] gids;
 
-        HashSet<String> loadedPermissions = new HashSet<String>();
-
         GrantedPermissions(int pkgFlags) {
             setFlags(pkgFlags);
         }
@@ -7561,6 +7552,7 @@
         PackageSignatures signatures = new PackageSignatures();
 
         boolean permissionsFixed;
+        boolean haveGids;
 
         /* Explicitly disabled components */
         HashSet<String> disabledComponents = new HashSet<String>(0);
@@ -7629,12 +7621,12 @@
         public void copyFrom(PackageSettingBase base) {
             grantedPermissions = base.grantedPermissions;
             gids = base.gids;
-            loadedPermissions = base.loadedPermissions;
 
             timeStamp = base.timeStamp;
             timeStampString = base.timeStampString;
             signatures = base.signatures;
             permissionsFixed = base.permissionsFixed;
+            haveGids = base.haveGids;
             disabledComponents = base.disabledComponents;
             enabledComponents = base.enabledComponents;
             enabled = base.enabled;
@@ -8063,7 +8055,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);
@@ -8168,7 +8159,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;
@@ -8177,7 +8168,6 @@
                 if (!used) {
                     // can safely delete this permission from list
                     sus.grantedPermissions.remove(eachPerm);
-                    sus.loadedPermissions.remove(eachPerm);
                 }
             }
             // Update gids
@@ -9052,7 +9042,7 @@
                         packageSetting.signatures.readXml(parser, mPastSignatures);
                     } else if (tagName.equals("perms")) {
                         readGrantedPermissionsLP(parser,
-                                packageSetting.loadedPermissions);
+                                packageSetting.grantedPermissions);
                         packageSetting.permissionsFixed = true;
                     } else {
                         reportSettingsProblem(Log.WARN,
@@ -9181,7 +9171,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>: "
@@ -9559,8 +9549,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
@@ -9590,11 +9578,10 @@
        if (doGc) {
            Runtime.getRuntime().gc();
        }
-       // Delete any stale containers if needed.
+       // List stale containers.
        if (removeCids != null) {
            for (String cid : removeCids) {
-               Log.i(TAG, "Destroying stale container : " + cid);
-               PackageHelper.destroySdDir(cid);
+               Log.w(TAG, "Container " + cid + " is stale");
            }
        }
    }
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/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 5bd23f4..4e506e7 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -45,6 +45,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.provider.Settings;
 import android.text.format.DateUtils;
 import android.text.format.Time;
 import android.util.Slog;
@@ -127,20 +128,39 @@
                     category = null;
                 }
                 if (category != null) {
+                    // This is the new activity that will serve as home while
+                    // we are in care mode.
                     intent = new Intent(Intent.ACTION_MAIN);
                     intent.addCategory(category);
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                             | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                    
+                    // Now we are going to be careful about switching the
+                    // configuration and starting the activity -- we need to
+                    // do this in a specific order under control of the
+                    // activity manager, to do it cleanly.  So compute the
+                    // new config, but don't set it yet, and let the
+                    // activity manager take care of both the start and config
+                    // change.
+                    Configuration newConfig = null;
+                    if (mHoldingConfiguration) {
+                        updateConfigurationLocked(false);
+                        newConfig = mConfiguration;
+                    }
                     try {
+                        ActivityManagerNative.getDefault().startActivityWithConfig(
+                                null, intent, null, null, 0, null, null, 0, false, false,
+                                newConfig);
                         mContext.startActivity(intent);
-                    } catch (ActivityNotFoundException e) {
+                        mHoldingConfiguration = false;
+                    } catch (RemoteException e) {
                         Slog.w(TAG, e.getCause());
                     }
                 }
 
                 if (mHoldingConfiguration) {
                     mHoldingConfiguration = false;
-                    updateConfigurationLocked();
+                    updateConfigurationLocked(true);
                 }
             }
         }
@@ -275,6 +295,9 @@
                 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
         mDeskModeKeepsScreenOn = (context.getResources().getInteger(
                 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
+        
+        mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
     }
 
     public void disableCarMode() {
@@ -319,6 +342,10 @@
             }
 
             if (mNightMode != mode) {
+                long ident = Binder.clearCallingIdentity();
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.UI_NIGHT_MODE, mode);
+                Binder.restoreCallingIdentity(ident);
                 mNightMode = mode;
                 updateLocked();
             }
@@ -360,7 +387,7 @@
         }
     }
 
-    final void updateConfigurationLocked() {
+    final void updateConfigurationLocked(boolean sendIt) {
         int uiMode = 0;
         if (mCarModeEnabled) {
             uiMode = Configuration.UI_MODE_TYPE_CAR;
@@ -385,13 +412,14 @@
 
         if (!mHoldingConfiguration && uiMode != mSetUiMode) {
             mSetUiMode = uiMode;
+            mConfiguration.uiMode = uiMode;
 
-            try {
-                final IActivityManager am = ActivityManagerNative.getDefault();
-                mConfiguration.uiMode = uiMode;
-                am.updateConfiguration(mConfiguration);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failure communicating with activity manager", e);
+            if (sendIt) {
+                try {
+                    ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failure communicating with activity manager", e);
+                }
             }
         }
     }
@@ -447,7 +475,7 @@
                 mHoldingConfiguration = true;
             }
 
-            updateConfigurationLocked();
+            updateConfigurationLocked(true);
 
             // keep screen on when charging and in car mode
             boolean keepScreenOn = mCharging &&
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7034c88..f734053 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3612,7 +3612,7 @@
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded,
-            boolean debug, WaitResult outResult) {
+            boolean debug, WaitResult outResult, Configuration config) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -3666,6 +3666,15 @@
                     grantedUriPermissions, grantedMode, aInfo,
                     resultTo, resultWho, requestCode, callingPid, callingUid,
                     onlyIfNeeded, componentSpecified);
+            if (config != null) {
+                // If the caller also wants to switch to a new configuration,
+                // do so now.  This allows a clean switch, as we are waiting
+                // for the current activity to pause (so we will not destroy
+                // it), and have not yet started the next activity.
+                enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+                        "updateConfiguration()");
+                updateConfigurationLocked(config, null);
+            }
             Binder.restoreCallingIdentity(origId);
             
             if (outResult != null) {
@@ -3707,8 +3716,9 @@
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded,
             boolean debug) {
-        return startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
-                grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, null);
+        return startActivityMayWait(caller, intent, resolvedType,
+                grantedUriPermissions, grantedMode, resultTo, resultWho,
+                requestCode, onlyIfNeeded, debug, null, null);
     }
 
     public final WaitResult startActivityAndWait(IApplicationThread caller,
@@ -3717,11 +3727,22 @@
             String resultWho, int requestCode, boolean onlyIfNeeded,
             boolean debug) {
         WaitResult res = new WaitResult();
-        startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
-                grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, res);
+        startActivityMayWait(caller, intent, resolvedType,
+                grantedUriPermissions, grantedMode, resultTo, resultWho,
+                requestCode, onlyIfNeeded, debug, res, null);
         return res;
     }
     
+    public final int startActivityWithConfig(IApplicationThread caller,
+            Intent intent, String resolvedType, Uri[] grantedUriPermissions,
+            int grantedMode, IBinder resultTo,
+            String resultWho, int requestCode, boolean onlyIfNeeded,
+            boolean debug, Configuration config) {
+        return startActivityMayWait(caller, intent, resolvedType,
+                grantedUriPermissions, grantedMode, resultTo, resultWho,
+                requestCode, onlyIfNeeded, debug, null, config);
+    }
+
      public int startActivityIntentSender(IApplicationThread caller,
             IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 166b6b6..5e1b82f 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -91,7 +91,6 @@
     private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
 
     private boolean mDunRequired;  // configuration info - must use DUN apn on 3g
-    private boolean mUseHiPri;
 
     private HierarchicalStateMachine mTetherMasterSM;
 
@@ -1052,13 +1051,12 @@
                 return false;
             }
             protected int turnOnMobileConnection() {
-                Log.d(TAG, "turnonMobileConnection with mUseHiPri="+mUseHiPri);
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                 IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
                 int retValue = Phone.APN_REQUEST_FAILED;
                 try {
                     retValue = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                            (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI : Phone.FEATURE_ENABLE_DUN),
+                            (mDunRequired ? Phone.FEATURE_ENABLE_DUN : Phone.FEATURE_ENABLE_HIPRI),
                             new Binder());
                 } catch (Exception e) {
                 }
@@ -1083,8 +1081,8 @@
                             IConnectivityManager.Stub.asInterface(b);
                     try {
                         service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                                (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI :
-                                             Phone.FEATURE_ENABLE_DUN));
+                                (mDunRequired? Phone.FEATURE_ENABLE_DUN :
+                                             Phone.FEATURE_ENABLE_HIPRI));
                     } catch (Exception e) {
                         return false;
                     }
@@ -1175,57 +1173,51 @@
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                 IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                 mConnectionRequested = false;
-                mUseHiPri = false;
                 Log.d(TAG, "chooseUpstreamType(" + tryCell + "),  dunRequired ="
                         + mDunRequired + ", iface=" + iface);
-                if (mDunRequired) {
-                    // check if Dun is on
+                if (iface != null) {
                     try {
-                        NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_DUN);
-                        if (info.isConnected()) {
-                            Log.d(TAG, "setting dun ifacename =" + iface);
-                            notifyTetheredOfNewIface(iface);
-                            // even if we're already connected - it may be somebody else's
-                            // refcount, so add our own
-                            turnOnMobileConnection();
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "RemoteException calling ConnectivityManager");
-                        notifyTetheredOfNewIface(null);
-                    }
-                    if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
-                        turnOnMobileConnection();
-                    }
-                } else {
-                    if (iface == null) {
-                        if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
-                            Log.d(TAG, "turning on hipri");
-                            mUseHiPri = true;
-                            turnOnMobileConnection(); // try to turn on hipri
-                        }
-
-                    } else {
-                        try {
+                        if (mDunRequired) {
+                            // check if Dun is on - we can use that
+                            NetworkInfo info = cm.getNetworkInfo(
+                                    ConnectivityManager.TYPE_MOBILE_DUN);
+                            if (info.isConnected()) {
+                                Log.d(TAG, "setting dun ifacename =" + iface);
+                                // even if we're already connected - it may be somebody else's
+                                // refcount, so add our own
+                                turnOnMobileConnection();
+                            } else {
+                                // verify the iface is not the default mobile - can't use that!
+                                info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+                                if (info.isConnected()) {
+                                    iface = null; // can't accept this one
+                                }
+                            }
+                        } else {
                             Log.d(TAG, "checking if hipri brought us this connection");
                             NetworkInfo info = cm.getNetworkInfo(
                                     ConnectivityManager.TYPE_MOBILE_HIPRI);
                             if (info.isConnected()) {
                                 Log.d(TAG, "yes - hipri in use");
-                                mUseHiPri = true;
+                                // even if we're already connected - it may be sombody else's
+                                // refcount, so add our own
                                 turnOnMobileConnection();
                             }
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "RemoteException calling ConnectivityManager");
                         }
-                        // we don't require Dun and have an iface that satisfies, so use it
-                        Log.d(TAG, "setting non-dun iface =" + iface);
-                        notifyTetheredOfNewIface(iface);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "RemoteException calling ConnectivityManager " + e);
+                        iface = null;
                     }
                 }
-                if (iface == null) {
+                // may have been set to null in the if above
+                if (iface == null ) {
+                    if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
+                        turnOnMobileConnection();
+                    }
                     // wait for things to settle and retry
                     sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
                 }
+                notifyTetheredOfNewIface(iface);
             }
             protected void notifyTetheredOfNewIface(String ifaceName) {
                 Log.d(TAG, "notifying tethered with iface =" + ifaceName);
@@ -1240,7 +1232,6 @@
         class InitialState extends TetherMasterUtilState {
             @Override
             public void enter() {
-                mUseHiPri = false;
                 mConnectionRequested = false;
             }
             @Override
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/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/apks/install_decl_perm/res/values/strings.xml b/tests/AndroidTests/apks/install_decl_perm/res/values/strings.xml
index 5564300..3b8b3b1 100644
--- a/tests/AndroidTests/apks/install_decl_perm/res/values/strings.xml
+++ b/tests/AndroidTests/apks/install_decl_perm/res/values/strings.xml
@@ -2,4 +2,5 @@
 
 <!-- Just need this dummy file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string name="dummy">dummy</string>
 </resources>
diff --git a/tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml b/tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml
index 5564300..3b8b3b1 100644
--- a/tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml
+++ b/tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml
@@ -2,4 +2,5 @@
 
 <!-- Just need this dummy file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string name="dummy">dummy</string>
 </resources>
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
index f2f7743..fa7b9ff 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
@@ -136,9 +136,7 @@
         if(localLOGV || TRACKING) Log.i(TAG, "blks3="+blks3);
         verifyTestFiles1(cacheDir, "testtmpdir", 5);
     }
-    
-    // TODO: flaky test
-    // @LargeTest
+
     public void testFreeApplicationCacheSomeFiles() throws Exception {
         StatFs st = new StatFs("/data");
         long blks1 = getFreeStorageBlks(st);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
index 9aed363..9a75047 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
@@ -259,6 +259,17 @@
         }
     }
 
+    public void testNonExistPath() {
+        IMountService ms = getMs();
+        try {
+            String path = ms.getSecureContainerPath("jparks.broke.it");
+            failStr(path);
+        } catch (IllegalArgumentException e) {
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
     public void testUnmountBusyContainer() {
         IMountService ms = getMs();
         try {
diff --git a/tests/LocationTracker/src/com/android/locationtracker/TrackerService.java b/tests/LocationTracker/src/com/android/locationtracker/TrackerService.java
index 5b75653..e2332bf 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/TrackerService.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/TrackerService.java
@@ -193,11 +193,11 @@
     }
 
     private boolean doDebugLogging() {
-        return getPreferences().getBoolean(DEBUG_PREF, true);
+        return getPreferences().getBoolean(DEBUG_PREF, false);
     }
 
     private boolean trackSignalStrength() {
-        return getPreferences().getBoolean(SIGNAL_PREF, true);
+        return getPreferences().getBoolean(SIGNAL_PREF, false);
     }
 
     private float getLocationMinDistance() {
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();