Merge change 25401 into eclair

* changes:
  Add a null checking to avoid crash.
diff --git a/Android.mk b/Android.mk
index 138ff09..4e7b14e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,8 @@
 	core/java/android/view/IWindow.aidl \
 	core/java/android/view/IWindowManager.aidl \
 	core/java/android/view/IWindowSession.aidl \
+	core/java/android/speech/IRecognitionListener.aidl \
+	core/java/android/speech/IRecognitionService.aidl \
 	core/java/android/speech/tts/ITts.aidl \
 	core/java/android/speech/tts/ITtsCallback.aidl \
 	core/java/com/android/internal/app/IBatteryStats.aidl \
diff --git a/api/current.xml b/api/current.xml
index 1713533..448da7c 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27401,6 +27401,87 @@
 >
 </method>
 </class>
+<class name="ParcelUuid"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="ParcelUuid"
+ type="android.bluetooth.ParcelUuid"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.util.UUID">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="fromString"
+ return="android.bluetooth.ParcelUuid"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.lang.String">
+</parameter>
+</method>
+<method name="getUuid"
+ return="java.util.UUID"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 </package>
 <package name="android.content"
 >
@@ -129363,6 +129444,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_TEXT_FLAG_NO_SUGGESTIONS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_TEXT_VARIATION_EMAIL_ADDRESS"
  type="int"
  transient="false"
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
index 83c7871..87fdc80 100644
--- a/cmds/keystore/netkeystore.c
+++ b/cmds/keystore/netkeystore.c
@@ -116,10 +116,13 @@
 
 static int is_alnum_string(char *s)
 {
+    char *s0 = s;
     while (*s != 0) {
-        if (!isalnum(*s++)) return 0;
+        if (!isalnum(*s++)) {
+            LOGE("The string '%s' is not an alphanumeric string\n", s0);
+            return 0;
+        }
     }
-    LOGE("The string %s is not an alphanumeric string\n", s);
     return 1;
 }
 
@@ -159,7 +162,9 @@
 // no argument
 static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
 {
-    reply->retcode = get_state();
+    int s = get_state();
+    if (DBG) LOGD("keystore state = %d\n", s);
+    reply->retcode = s;
 }
 
 // args of listkeys():
@@ -413,12 +418,10 @@
 
         // read the command, execute and send the result back.
         if(read_marshal(s, &cmd)) goto err;
-        if (DBG) LOGD("new connection\n");
         execute(&cmd, &reply);
         write_marshal(s, &reply);
 err:
         memset(&reply, 0, sizeof(LPC_MARSHAL));
-        if (DBG) LOGD("closing connection\n");
         close(s);
     }
 
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 0bdcc1d..4217957 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -46,7 +46,6 @@
 import android.app.PendingIntent;
 import android.app.NotificationManager;
 import android.app.Notification;
-import android.app.Activity;
 import android.Manifest;
 
 import java.io.FileDescriptor;
@@ -471,6 +470,7 @@
     }
 
     private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
+        cancelNotification(getSigninRequiredNotificationId(account));
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         db.beginTransaction();
         try {
@@ -523,7 +523,7 @@
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         try {
-            cacheAuthToken(account, authTokenType, authToken);
+            saveAuthTokenToDatabase(account, authTokenType, authToken);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -686,7 +686,8 @@
                                         "the type and name should not be empty");
                                 return;
                             }
-                            cacheAuthToken(new Account(name, type), authTokenType, authToken);
+                            saveAuthTokenToDatabase(new Account(name, type),
+                                    authTokenType, authToken);
                         }
 
                         Intent intent = result.getParcelable(Constants.INTENT_KEY);
@@ -1004,10 +1005,6 @@
         }
     }
 
-    private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
-        return saveAuthTokenToDatabase(account, authTokenType, authToken);
-    }
-
     private long getAccountId(SQLiteDatabase db, Account account) {
         Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
                 "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 75a90c4..1209d0f 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -739,11 +739,6 @@
             return false;
         }
 
-        // handle back key to go back to previous searchable, etc.
-        if (handleBackKey(keyCode, event)) {
-            return true;
-        }
-        
         if (keyCode == KeyEvent.KEYCODE_SEARCH) {
             // Consume search key for later use.
             return true;
@@ -756,8 +751,8 @@
             launchQuerySearch(keyCode, actionKey.getQueryActionMsg());
             return true;
         }
-        
-        return false;
+
+        return super.onKeyDown(keyCode, event);
     }
     
     @Override
@@ -767,11 +762,6 @@
             return false;
         }
 
-        // handle back key to go back to previous searchable, etc.
-        if (handleBackKey(keyCode, event)) {
-            return true;
-        }
-        
         if (keyCode == KeyEvent.KEYCODE_SEARCH && event.isTracking()
                 && !event.isCanceled()) {
             // If the search key is pressed, toggle between global and in-app search. If we are
@@ -779,8 +769,8 @@
             // just don't do anything.
             return toggleGlobalSearch();
         }
-        
-        return false;
+
+        return super.onKeyUp(keyCode, event);
     }
     
     /**
@@ -1488,6 +1478,13 @@
     }
 
     /**
+     * Checks if there are any previous searchable components in the history stack.
+     */
+    private boolean hasPreviousComponent() {
+        return mPreviousComponents != null && !mPreviousComponents.isEmpty();
+    }
+
+    /**
      * Saves the previous component that was searched, so that we can go
      * back to it.
      */
@@ -1505,14 +1502,10 @@
      *         no previous component.
      */
     private ComponentName popPreviousComponent() {
-        if (mPreviousComponents == null) {
+        if (!hasPreviousComponent()) {
             return null;
         }
-        int size = mPreviousComponents.size();
-        if (size == 0) {
-            return null;
-        }
-        return mPreviousComponents.remove(size - 1);
+        return mPreviousComponents.remove(mPreviousComponents.size() - 1);
     }
     
     /**
@@ -1520,25 +1513,22 @@
      * 
      * @return <code>true</code> if there was a previous component that we could go back to.
      */
-    private boolean backToPreviousComponent(boolean doIt) {
+    private boolean backToPreviousComponent() {
         ComponentName previous = popPreviousComponent();
         if (previous == null) {
             return false;
         }
-        
-        if (doIt) {
-            if (!show(previous, mAppSearchData, false)) {
-                Log.w(LOG_TAG, "Failed to switch to source " + previous);
-                return false;
-            }
-            
-            // must touch text to trigger suggestions
-            // TODO: should this be the text as it was when the user left
-            // the source that we are now going back to?
-            String query = mSearchAutoComplete.getText().toString();
-            setUserQuery(query);
+
+        if (!show(previous, mAppSearchData, false)) {
+            Log.w(LOG_TAG, "Failed to switch to source " + previous);
+            return false;
         }
-        
+
+        // must touch text to trigger suggestions
+        // TODO: should this be the text as it was when the user left
+        // the source that we are now going back to?
+        String query = mSearchAutoComplete.getText().toString();
+        setUserQuery(query);
         return true;
     }
     
@@ -1763,74 +1753,49 @@
          */
         @Override
         public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+            if (DBG) Log.d(LOG_TAG, "onKeyPreIme(" + keyCode + "," + event + ")");
             if (mSearchDialog.mSearchable == null) {
                 return false;
             }
             if (keyCode == KeyEvent.KEYCODE_BACK) {
                 if (event.getAction() == KeyEvent.ACTION_DOWN
                         && event.getRepeatCount() == 0) {
-                    // We release the back key, might we want to do
-                    // something before the IME?
-                    if (mSearchDialog.backToPreviousComponent(false)) {
+                    if (mSearchDialog.hasPreviousComponent() || isDismissingKeyboardPointless()) {
                         getKeyDispatcherState().startTracking(event, this);
                         return true;
                     }
-                    if (isInputMethodNotNeeded() ||
-                            (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
-                        getKeyDispatcherState().startTracking(event, this);
-                        return true;
-                    }
-                    return false; // will dismiss soft keyboard if necessary
                 } else if (event.getAction() == KeyEvent.ACTION_UP
                         && event.isTracking() && !event.isCanceled()) {
-                    if (mSearchDialog.backToPreviousComponent(true)) {
+                    if (mSearchDialog.backToPreviousComponent()) {
                         return true;
-                    }
-                    // If the drop-down obscures the keyboard, the user wouldn't see anything
-                    // happening when pressing back, so we dismiss the entire dialog instead.
-                    //
-                    // also: if there is no text entered, we also want to dismiss the whole dialog,
-                    // not just the soft keyboard.  the exception to this is if there are shortcuts
-                    // that aren't displayed (e.g are being obscured by the soft keyboard); in that
-                    // case we want to dismiss the soft keyboard so the user can see the rest of the
-                    // shortcuts.
-                    if (isInputMethodNotNeeded() ||
-                            (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
+                    } else if (isDismissingKeyboardPointless()) {
                         mSearchDialog.cancel();
                         return true;
                     }
-                    return false; // will dismiss soft keyboard if necessary
                 }
             }
             return false;
         }
 
+        // If the drop-down obscures the keyboard, or if the drop-down shows all suggestions,
+        // dismissing the keyboard is pointless, so we dismiss the entire dialog instead.
+        private boolean isDismissingKeyboardPointless() {
+            return (isInputMethodNotNeeded() || getDropDownChildCount() >= getAdapterCount());
+        }
+
         private int getAdapterCount() {
             final ListAdapter adapter = getAdapter();
             return adapter == null ? 0 : adapter.getCount();
         }
     }
-    
-    protected boolean handleBackKey(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            if (event.getAction() == KeyEvent.ACTION_DOWN
-                    && event.getRepeatCount() == 0) {
-                // Consume the event, to get an up at which point we execute.
-                event.startTracking();
-                return true;
-            }
-            if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking()
-                    && !event.isCanceled()) {
-                if (backToPreviousComponent(true)) {
-                    return true;
-                }
-                cancel();
-            }
-            return true;
+
+    @Override
+    public void onBackPressed() {
+        if (!backToPreviousComponent()) {
+            cancel();
         }
-        return false;
     }
-    
+
     /**
      * Implements OnItemClickListener
      */
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index b1861ac..0b3f3c7 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -503,7 +503,7 @@
     }
 
     /** @hide */
-     public String[] getUuids() {
+     public ParcelUuid[] getUuids() {
         try {
             return sService.getRemoteUuids(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -511,7 +511,7 @@
     }
 
     /** @hide */
-    public int getServiceChannel(String uuid) {
+    public int getServiceChannel(ParcelUuid uuid) {
          try {
              return sService.getRemoteServiceChannel(mAddress, uuid);
          } catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index c15bc20..409c744 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -16,10 +16,11 @@
 
 package android.bluetooth;
 
-import java.util.UUID;
+import java.util.Arrays;
+import java.util.HashSet;
 
 /**
-* Static helper methods and constants to decode the UUID of remote devices.
+* Static helper methods and constants to decode the ParcelUuid of remote devices.
 *  @hide
 */
 public final class BluetoothUuid {
@@ -30,40 +31,99 @@
      * The following 128 bit values are calculated as:
      *  uuid * 2^96 + BASE_UUID
      */
-    public static final UUID AudioSink = UUID.fromString("0000110B-0000-1000-8000-00805F9B34FB");
-    public static final UUID AudioSource = UUID.fromString("0000110A-0000-1000-8000-00805F9B34FB");
-    public static final UUID AdvAudioDist = UUID.fromString("0000110D-0000-1000-8000-00805F9B34FB");
-    public static final UUID HSP       = UUID.fromString("00001108-0000-1000-8000-00805F9B34FB");
-    public static final UUID Handsfree  = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
-    public static final UUID AvrcpController =
-                                          UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
-    public static final UUID AvrcpTarget = UUID.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AudioSink =
+            ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AudioSource =
+            ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AdvAudioDist =
+            ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid HSP =
+            ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid Handsfree =
+            ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AvrcpController =
+            ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AvrcpTarget =
+            ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid ObexObjectPush =
+            ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
 
-    public static boolean isAudioSource(UUID uuid) {
+    public static boolean isAudioSource(ParcelUuid uuid) {
         return uuid.equals(AudioSource);
     }
 
-    public static boolean isAudioSink(UUID uuid) {
+    public static boolean isAudioSink(ParcelUuid uuid) {
         return uuid.equals(AudioSink);
     }
 
-    public static boolean isAdvAudioDist(UUID uuid) {
+    public static boolean isAdvAudioDist(ParcelUuid uuid) {
         return uuid.equals(AdvAudioDist);
     }
 
-    public static boolean isHandsfree(UUID uuid) {
+    public static boolean isHandsfree(ParcelUuid uuid) {
         return uuid.equals(Handsfree);
     }
 
-    public static boolean isHeadset(UUID uuid) {
+    public static boolean isHeadset(ParcelUuid uuid) {
         return uuid.equals(HSP);
     }
 
-    public static boolean isAvrcpController(UUID uuid) {
+    public static boolean isAvrcpController(ParcelUuid uuid) {
         return uuid.equals(AvrcpController);
     }
 
-    public static boolean isAvrcpTarget(UUID uuid) {
+    public static boolean isAvrcpTarget(ParcelUuid uuid) {
         return uuid.equals(AvrcpTarget);
     }
+
+    /**
+     * Returns true if ParcelUuid is present in uuidArray
+     *
+     * @param uuidArray - Array of ParcelUuids
+     * @param uuid
+     */
+    public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
+        for (ParcelUuid element: uuidArray) {
+            if (element.equals(uuid)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if there any common ParcelUuids in uuidA and uuidB.
+     *
+     * @param uuidA - List of ParcelUuids
+     * @param uuidB - List of ParcelUuids
+     *
+     */
+    public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+        if (uuidA == null && uuidB == null) return true;
+        if (uuidA == null || uuidB == null) return false;
+
+        HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
+        for (ParcelUuid uuid: uuidB) {
+            if (uuidSet.contains(uuid)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if all the ParcelUuids in ParcelUuidB are present in
+     * ParcelUuidA
+     *
+     * @param uuidA - Array of ParcelUuidsA
+     * @param uuidB - Array of ParcelUuidsB
+     *
+     */
+    public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+        if (uuidA == null && uuidB == null) return true;
+        if (uuidA == null || uuidB == null) return false;
+
+        HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
+        for (ParcelUuid uuid: uuidB) {
+            if (!uuidSet.contains(uuid)) return false;
+        }
+        return true;
+    }
+
 }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a11ceac..04c8ec9 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.bluetooth.ParcelUuid;
+
 /**
  * System private API for talking with the Bluetooth service.
  *
@@ -50,8 +52,8 @@
 
     String getRemoteName(in String address);
     int getRemoteClass(in String address);
-    String[] getRemoteUuids(in String address);
-    int getRemoteServiceChannel(in String address, String uuid);
+    ParcelUuid[] getRemoteUuids(in String address);
+    int getRemoteServiceChannel(in String address,in ParcelUuid uuid);
 
     boolean setPin(in String address, in byte[] pin);
     boolean setPasskey(in String address, int passkey);
diff --git a/core/java/android/bluetooth/ParcelUuid.aidl b/core/java/android/bluetooth/ParcelUuid.aidl
new file mode 100644
index 0000000..70bcc4b
--- /dev/null
+++ b/core/java/android/bluetooth/ParcelUuid.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable ParcelUuid;
diff --git a/core/java/android/bluetooth/ParcelUuid.java b/core/java/android/bluetooth/ParcelUuid.java
new file mode 100644
index 0000000..27166a0
--- /dev/null
+++ b/core/java/android/bluetooth/ParcelUuid.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.UUID;
+
+/**
+ * This class is a Parcelable wrapper around {@link UUID} which is an
+ * immutable representation of a 128-bit universally unique
+ * identifier.
+ */
+public final class ParcelUuid implements Parcelable {
+
+    private final UUID mUuid;
+
+    /**
+     * Constructor creates a ParcelUuid instance from the
+     * given {@link UUID}.
+     *
+     * @param uuid UUID
+     */
+    public ParcelUuid(UUID uuid) {
+        mUuid = uuid;
+    }
+
+    /**
+     * Creates a new ParcelUuid from a string representation of {@link UUID}.
+     *
+     * @param uuid
+     *            the UUID string to parse.
+     * @return an ParcelUuid instance.
+     * @throws NullPointerException
+     *             if {@code uuid} is {@code null}.
+     * @throws IllegalArgumentException
+     *             if {@code uuid} is not formatted correctly.
+     */
+    public static ParcelUuid fromString(String uuid) {
+        return new ParcelUuid(UUID.fromString(uuid));
+    }
+
+    /**
+     * Get the {@link UUID} represented by the ParcelUuid.
+     *
+     * @return UUID contained in the ParcelUuid.
+     */
+    public UUID getUuid() {
+        return mUuid;
+    }
+
+    /**
+     * Returns a string representation of the ParcelUuid
+     * For example: 0000110B-0000-1000-8000-00805F9B34FB will be the return value.
+     *
+     * @return a String instance.
+     */
+    @Override
+    public String toString() {
+        return mUuid.toString();
+    }
+
+
+   @Override
+   public int hashCode() {
+       return mUuid.hashCode();
+   }
+
+   /**
+    * Compares this ParcelUuid to another object for equality. If {@code object}
+    * is not {@code null}, is a ParcelUuid instance, and all bits are equal, then
+    * {@code true} is returned.
+    *
+    * @param object
+    *            the {@code Object} to compare to.
+    * @return {@code true} if this ParcelUuid is equal to {@code object}
+    *         or {@code false} if not.
+    */
+   @Override
+   public boolean equals(Object object) {
+       if (object == null) {
+           return false;
+       }
+
+       if (this == object) {
+           return true;
+       }
+
+       if (!(object instanceof ParcelUuid)) {
+           return false;
+       }
+
+       ParcelUuid that = (ParcelUuid) object;
+
+       return (this.mUuid.equals(that.mUuid));
+   }
+
+   public static final Parcelable.Creator<ParcelUuid> CREATOR =
+               new Parcelable.Creator<ParcelUuid>() {
+        public ParcelUuid createFromParcel(Parcel source) {
+            long mostSigBits = source.readLong();
+            long leastSigBits = source.readLong();
+            UUID uuid = new UUID(mostSigBits, leastSigBits);
+            return new ParcelUuid(uuid);
+        }
+
+        public ParcelUuid[] newArray(int size) {
+            return new ParcelUuid[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mUuid.getMostSignificantBits());
+        dest.writeLong(mUuid.getLeastSignificantBits());
+    }
+}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index afa0a7c..6eaf9dd 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1039,6 +1039,7 @@
             public static final int TYPE_WORK_MOBILE = 17;
             public static final int TYPE_WORK_PAGER = 18;
             public static final int TYPE_ASSISTANT = 19;
+            public static final int TYPE_MMS = 20;
 
             /**
              * The phone number as the user entered it.
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 9c687e2..be8c777 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -27,6 +27,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothA2dp;
+import android.bluetooth.ParcelUuid;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -42,7 +43,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.UUID;
 
 public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
     private static final String TAG = "BluetoothA2dpService";
@@ -188,15 +188,9 @@
     }
 
     private boolean isSinkDevice(BluetoothDevice device) {
-        String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress());
-        UUID uuid;
-        if (uuids != null) {
-            for (String deviceUuid: uuids) {
-                uuid = UUID.fromString(deviceUuid);
-                if (BluetoothUuid.isAudioSink(uuid)) {
-                    return true;
-                }
-            }
+        ParcelUuid[] uuids = mBluetoothService.getRemoteUuids(device.getAddress());
+        if (uuids != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
+            return true;
         }
         return false;
     }
@@ -229,18 +223,14 @@
             for (String path: paths) {
                 String address = mBluetoothService.getAddressFromObjectPath(path);
                 BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                String []uuids = mBluetoothService.getRemoteUuids(address);
-                if (uuids != null)
-                    for (String uuid: uuids) {
-                        UUID remoteUuid = UUID.fromString(uuid);
-                        if (BluetoothUuid.isAudioSink(remoteUuid) ||
-                            BluetoothUuid.isAudioSource(remoteUuid) ||
-                            BluetoothUuid.isAdvAudioDist(remoteUuid)) {
-                            addAudioSink(device);
-                            break;
-                        }
+                ParcelUuid[] remoteUuids = mBluetoothService.getRemoteUuids(address);
+                if (remoteUuids != null)
+                    if (BluetoothUuid.containsAnyUuid(remoteUuids,
+                            new ParcelUuid[] {BluetoothUuid.AudioSink,
+                                                BluetoothUuid.AdvAudioDist})) {
+                        addAudioSink(device);
                     }
-            }
+                }
         }
         mAudioManager.setParameters(BLUETOOTH_ENABLED+"=true");
     }
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1ed5c49..ba53307 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -21,6 +21,7 @@
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothUuid;
+import android.bluetooth.ParcelUuid;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
@@ -28,7 +29,6 @@
 import android.util.Log;
 
 import java.util.HashMap;
-import java.util.UUID;
 
 /**
  * TODO: Move this to
@@ -501,7 +501,7 @@
         }
 
         boolean authorized = false;
-        UUID uuid = UUID.fromString(deviceUuid);
+        ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
         // Bluez sends the UUID of the local service being accessed, _not_ the
         // remote service
         if (mBluetoothService.isEnabled() &&
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index de0cad7..c0e4f34 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -24,11 +24,12 @@
 
 package android.server;
 
-import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.IBluetooth;
+import android.bluetooth.ParcelUuid;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -51,7 +52,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 
 public class BluetoothService extends IBluetooth.Stub {
@@ -967,22 +967,26 @@
 
 
     /**
-     * Gets the remote features encoded as bit mask.
+     * Gets the UUIDs supported by the remote device
      *
-     * Note: This method may be obsoleted soon.
-     *
-     * @return String array of 128bit UUIDs
+     * @return array of 128bit ParcelUuids
      */
-    public synchronized String[] getRemoteUuids(String address) {
+    public synchronized ParcelUuid[] getRemoteUuids(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return null;
         }
         String value = getRemoteDeviceProperty(address, "UUIDs");
-        String[] uuids = null;
+        if (value == null) return null;
+
+        String[] uuidStrings = null;
         // The UUIDs are stored as a "," separated string.
-        if (value != null)
-             uuids = value.split(",");
+        uuidStrings = value.split(",");
+        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
+
+        for (int i = 0; i < uuidStrings.length; i++) {
+            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
+        }
         return uuids;
     }
 
@@ -990,16 +994,17 @@
      * Gets the rfcomm channel associated with the UUID.
      *
      * @param address Address of the remote device
-     * @param uuid UUID of the service attribute
+     * @param uuid ParcelUuid of the service attribute
      *
      * @return rfcomm channel associated with the service attribute
      */
-    public int getRemoteServiceChannel(String address, String uuid) {
+    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return BluetoothDevice.ERROR;
         }
-        return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid, 0x0004);
+        return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
+                0x0004);
     }
 
     public synchronized boolean setPin(String address, byte[] pin) {
@@ -1148,11 +1153,11 @@
                        mBondState.getAttempt(address),
                        getRemoteName(address));
             if (bondState == BluetoothDevice.BOND_BONDED) {
-                String[] uuids = getRemoteUuids(address);
+                ParcelUuid[] uuids = getRemoteUuids(address);
                 if (uuids == null) {
                     pw.printf("\tuuids = null\n");
                 } else {
-                    for (String uuid : uuids) {
+                    for (ParcelUuid uuid : uuids) {
                         pw.printf("\t" + uuid + "\n");
                     }
                 }
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
new file mode 100644
index 0000000..2da2258
--- /dev/null
+++ b/core/java/android/speech/IRecognitionListener.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.os.Bundle;
+import android.speech.RecognitionResult;
+
+/**
+ * Listener for speech recognition events, used with RecognitionService.
+ *  This gives you both the final recognition results, as well as various
+ *  intermediate events that can be used to show visual feedback to the user.
+ *  {@hide}
+ */
+interface IRecognitionListener {
+    /** Called when the endpointer is ready for the user to start speaking. */
+    void onReadyForSpeech(in Bundle noiseParams);
+
+    /** The user has started to speak. */
+    void onBeginningOfSpeech();
+
+    /** The sound level in the audio stream has changed. */
+    void onRmsChanged(in float rmsdB);
+
+    /**
+     * More sound has been received. Buffer is a byte buffer containing
+     * a sequence of 16-bit shorts. 
+     */
+    void onBufferReceived(in byte[] buffer);
+
+    /** Called after the user stops speaking. */
+    void onEndOfSpeech();
+
+    /**
+     * A network or recognition error occurred. The code is defined in
+     * {@link android.speech.RecognitionResult}
+     */
+    void onError(in int error);
+
+    /** 
+     * Called when recognition results are ready.
+     * @param results: an ordered list of the most likely results (N-best list).
+     * @param key: a key associated with the results. The same results can
+     * be retrieved asynchronously later using the key, if available. 
+     */
+    void onResults(in List<RecognitionResult> results, long key);
+}
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
new file mode 100644
index 0000000..a18c380
--- /dev/null
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.content.Intent;
+import android.speech.IRecognitionListener;
+import android.speech.RecognitionResult;
+
+// A Service interface to speech recognition. Call startListening when
+// you want to begin capturing audio; RecognitionService will automatically
+// determine when the user has finished speaking, stream the audio to the
+// recognition servers, and notify you when results are ready.
+/** {@hide} */
+interface IRecognitionService {
+    // Start listening for speech. Can only call this from one thread at once.
+    // see RecognizerIntent.java for constants used to specify the intent.
+    void startListening(in Intent recognizerIntent,
+        in IRecognitionListener listener);
+        
+    List<RecognitionResult> getRecognitionResults(in long key);
+
+    void cancel();
+}
diff --git a/core/java/android/speech/RecognitionResult.aidl b/core/java/android/speech/RecognitionResult.aidl
new file mode 100644
index 0000000..59e53ab
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+parcelable RecognitionResult;
diff --git a/core/java/android/speech/RecognitionResult.java b/core/java/android/speech/RecognitionResult.java
new file mode 100644
index 0000000..95715ee
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * RecognitionResult is a passive object that stores a single recognized query
+ * and its search result.
+ * 
+ * TODO: Revisit and improve this class, reconciling the different types of actions and
+ * the different ways they are represented. Maybe we should have a separate result object
+ * for each type, and put them (type/value) in bundle?
+ * {@hide}
+ */
+public class RecognitionResult implements Parcelable {
+    /**
+     * Status of the recognize request.
+     */
+    public static final int NETWORK_TIMEOUT = 1; // Network operation timed out.
+
+    public static final int NETWORK_ERROR = 2; // Other network related errors.
+
+    public static final int AUDIO_ERROR = 3; // Audio recording error.
+
+    public static final int SERVER_ERROR = 4; // Server sends error status.
+
+    public static final int CLIENT_ERROR = 5; // Other client side errors.
+
+    public static final int SPEECH_TIMEOUT = 6; // No speech input
+
+    public static final int NO_MATCH = 7; // No recognition result matched.
+
+    public static final int SERVICE_BUSY = 8; // RecognitionService busy.
+
+    /**
+     * Type of the recognition results.
+     */
+    public static final int RAW_RECOGNITION_RESULT = 0;
+
+    public static final int WEB_SEARCH_RESULT = 1;
+
+    public static final int CONTACT_RESULT = 2;
+    
+    public static final int ACTION_RESULT = 3;
+
+    /**
+     * A factory method to create a raw RecognitionResult
+     * 
+     * @param sentence the recognized text.
+     */
+    public static RecognitionResult newRawRecognitionResult(String sentence) {
+        return new RecognitionResult(RAW_RECOGNITION_RESULT, sentence, null, null);
+    }
+
+    /**
+     * A factory method to create a RecognitionResult for contacts.
+     * 
+     * @param contact the contact name.
+     * @param phoneType the phone type.
+     * @param callAction whether this result included a command to "call", or
+     *            just the contact name.
+     */
+    public static RecognitionResult newContactResult(String contact, int phoneType,
+            boolean callAction) {
+        return new RecognitionResult(CONTACT_RESULT, contact, phoneType, callAction);
+    }
+
+    /**
+     * A factory method to create a RecognitionResult for a web search query.
+     * 
+     * @param query the query string.
+     * @param html the html page of the search result.
+     * @param url the url that performs the search with the query.
+     */
+    public static RecognitionResult newWebResult(String query, String html, String url) {
+        return new RecognitionResult(WEB_SEARCH_RESULT, query, html, url);
+    }
+    
+    /**
+     * A factory method to create a RecognitionResult for an action.
+     * 
+     * @param action the action type
+     * @param query the query string associated with that action.
+     */
+    public static RecognitionResult newActionResult(int action, String query) {
+        return new RecognitionResult(ACTION_RESULT, action, query);
+    }
+
+    public static final Parcelable.Creator<RecognitionResult> CREATOR =
+            new Parcelable.Creator<RecognitionResult>() {
+
+                public RecognitionResult createFromParcel(Parcel in) {
+                    return new RecognitionResult(in);
+                }
+        
+                public RecognitionResult[] newArray(int size) {
+                    return new RecognitionResult[size];
+                }
+            };
+
+    /**
+     * Result type.
+     */
+    public final int mResultType;
+
+    /**
+     * The recognized string when mResultType is WEB_SEARCH_RESULT. The name of
+     * the contact when mResultType is CONTACT_RESULT. The relevant query when
+     * mResultType is ACTION_RESULT.
+     */
+    public final String mText;
+
+    /**
+     * The HTML result page for the query. If this is null, then the application
+     * must use the url field to get the HTML result page.
+     */
+    public final String mHtml;
+
+    /**
+     * The url to get the result page for the query string. The application must
+     * use this url instead of performing the search with the query.
+     */
+    public final String mUrl;
+
+    /**
+     * Phone number type. This is valid only when mResultType == CONTACT_RESULT.
+     */
+    public final int mPhoneType;
+    
+    /**
+     * Action type.  This is valid only when mResultType == ACTION_RESULT.
+     */
+    public final int mAction;
+
+    /**
+     * Whether a contact recognition result included a command to "call". This
+     * is valid only when mResultType == CONTACT_RESULT.
+     */
+    public final boolean mCallAction;
+
+    private RecognitionResult(int type, int action, String query) {
+        mResultType = type;
+        mAction = action;
+        mText = query;
+        mHtml = null;
+        mUrl = null;
+        mPhoneType = -1;
+        mCallAction = false;
+    }
+    
+    private RecognitionResult(int type, String query, String html, String url) {
+        mResultType = type;
+        mText = query;
+        mHtml = html;
+        mUrl = url;
+        mPhoneType = -1;
+        mAction = -1;
+        mCallAction = false;
+    }
+
+    private RecognitionResult(int type, String query, int phoneType, boolean callAction) {
+        mResultType = type;
+        mText = query;
+        mPhoneType = phoneType;
+        mHtml = null;
+        mUrl = null;
+        mAction = -1;
+        mCallAction = callAction;
+    }
+
+    private RecognitionResult(Parcel in) {
+        mResultType = in.readInt();
+        mText = in.readString();
+        mHtml = in.readString();
+        mUrl = in.readString();
+        mPhoneType = in.readInt();
+        mAction = in.readInt();
+        mCallAction = (in.readInt() == 1);
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mResultType);
+        out.writeString(mText);
+        out.writeString(mHtml);
+        out.writeString(mUrl);
+        out.writeInt(mPhoneType);
+        out.writeInt(mAction);
+        out.writeInt(mCallAction ? 1 : 0);
+    }
+
+    @Override
+    public String toString() {
+        String resultType[] = {
+                "RAW", "WEB", "CONTACT", "ACTION"
+        };
+        return "[type=" + resultType[mResultType] + ", text=" + mText + ", mUrl=" + mUrl
+                + ", html=" + mHtml + ", mAction=" + mAction + ", mCallAction=" + mCallAction + "]";
+    }
+
+    public int describeContents() {
+        // no special description
+        return 0;
+    }
+}
diff --git a/core/java/android/speech/RecognitionServiceUtil.java b/core/java/android/speech/RecognitionServiceUtil.java
new file mode 100644
index 0000000..4207543
--- /dev/null
+++ b/core/java/android/speech/RecognitionServiceUtil.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.speech.RecognitionResult;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Utils for Google's network-based speech recognizer, which lets you perform
+ * speech-to-text translation through RecognitionService. IRecognitionService
+ * and IRecognitionListener are the core interfaces; you begin recognition
+ * through IRecognitionService and subscribe to callbacks about when the user
+ * stopped speaking, results come in, errors, etc. through IRecognitionListener.
+ * RecognitionServiceUtil includes default IRecognitionListener and
+ * ServiceConnection implementations to reduce the amount of boilerplate.
+ *
+ * The Service provides no user interface. See RecognitionActivity if you
+ * want the standard voice search UI.
+ *
+ * Below is a small skeleton of how to use the recognizer:
+ *
+ * ServiceConnection conn = new RecognitionServiceUtil.Connection();
+ * mContext.bindService(RecognitionServiceUtil.sDefaultIntent,
+ *     conn, Context.BIND_AUTO_CREATE);
+ * IRecognitionListener listener = new RecognitionServiceWrapper.NullListener() {
+ *         public void onResults(List<String> results) {
+ *             // Do something with recognition transcripts
+ *         }
+ *     }
+ *
+ * // Must wait for conn.mService to be populated, then call below
+ * conn.mService.startListening(null, listener);
+ *
+ * {@hide}
+ */
+public class RecognitionServiceUtil {
+    public static final Intent sDefaultIntent = new Intent(
+            RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+
+    // Recognize request parameters
+    public static final String USE_LOCATION = "useLocation";
+    public static final String CONTACT_AUTH_TOKEN = "contactAuthToken";
+    
+    // Bundles
+    public static final String NOISE_LEVEL = "NoiseLevel";
+    public static final String SIGNAL_NOISE_RATIO = "SignalNoiseRatio";
+
+    private RecognitionServiceUtil() {}
+
+    /**
+     * IRecognitionListener which does nothing in response to recognition
+     * callbacks. You can subclass from this and override only the methods
+     * whose events you want to respond to.
+     */
+    public static class NullListener extends IRecognitionListener.Stub {
+        public void onReadyForSpeech(Bundle bundle) {}
+        public void onBeginningOfSpeech() {}
+        public void onRmsChanged(float rmsdB) {}
+        public void onBufferReceived(byte[] buf) {}
+        public void onEndOfSpeech() {}
+        public void onError(int error) {}
+        public void onResults(List<RecognitionResult> results, long key) {}
+    }
+
+    /**
+     * Basic ServiceConnection which just records mService variable.
+     */
+    public static class Connection implements ServiceConnection {
+        public IRecognitionService mService;
+
+        public synchronized void onServiceConnected(ComponentName name, IBinder service) {
+            mService = IRecognitionService.Stub.asInterface(service);
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            mService = null;
+        }
+    }
+}
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index d50684a..14b8308 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -128,6 +128,15 @@
      */
     public static final int TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000;
     
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: the input method does not need to
+     * display any dictionary-based candidates. This is useful for text views that
+     * do not contain words from the language and do not benefit from any
+     * dictionary-based completions or corrections. It overrides the
+     * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set.
+     */
+    public static final int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000;
+
     // ----------------------------------------------------------------------
     
     /**
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 38881d3..f736f85 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -431,6 +431,7 @@
         PICKER_SETS.put('z', "\u017A\u017C\u017E");
         PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
                              "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\");
+        PICKER_SETS.put('/', "\\");
 
         // From packages/inputmethods/LatinIME/res/xml/kbd_symbols.xml
 
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 5a164f8..14bc33b 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -17,8 +17,18 @@
 package android.webkit;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnPreparedListener;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.net.http.EventHandler;
+import android.net.http.Headers;
+import android.net.http.RequestHandle;
+import android.net.http.RequestQueue;
+import android.net.http.SslCertificate;
+import android.net.http.SslError;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,9 +40,12 @@
 import android.view.ViewGroup;
 import android.webkit.ViewManager.ChildView;
 import android.widget.AbsoluteLayout;
+import android.widget.ImageView;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.HashMap;
 
 /**
@@ -45,108 +58,216 @@
     // Message Ids for WebCore thread -> UI thread communication.
     private static final int INIT              = 100;
     private static final int PLAY              = 101;
+    private static final int SET_POSTER        = 102;
 
+    // Message Ids to be handled on the WebCore thread
+
+    // The handler for WebCore thread messages;
+    private Handler mWebCoreHandler;
     // The WebView instance that created this view.
     private WebView mWebView;
     // The ChildView instance used by the ViewManager.
     private ChildView mChildView;
-    // The VideoView instance. Note that we could
-    // also access this via mChildView.mView but it would
-    // always require cast, so it is more convenient to store
-    // it here as well.
-    private HTML5VideoView mVideoView;
+    // The poster image to be shown when the video is not playing.
+    private ImageView mPosterView;
+    // The poster downloader.
+    private PosterDownloader mPosterDownloader;
+    // A helper class to control the playback. This executes on the UI thread!
+    private static final class VideoPlayer {
+        // The proxy that is currently playing (if any).
+        private static HTML5VideoViewProxy mCurrentProxy;
+        // The VideoView instance. This is a singleton for now, at least until
+        // http://b/issue?id=1973663 is fixed.
+        private static VideoView mVideoView;
 
-    // A VideoView subclass that responds to double-tap
-    // events by going fullscreen.
-    class HTML5VideoView extends VideoView {
-        // Used to save the layout parameters if the view
-        // is changed to fullscreen.
-        private AbsoluteLayout.LayoutParams mEmbeddedLayoutParams;
-        // Flag that denotes whether the view is fullscreen or not.
-        private boolean mIsFullscreen;
-        // Used to save the current playback position when
-        // transitioning to/from fullscreen.
-        private int mPlaybackPosition;
-        // The callback object passed to the host application. This callback
-        // is invoked when the host application dismisses our VideoView
-        // (e.g. the user presses the back key).
-        private WebChromeClient.CustomViewCallback mCallback =
-                new WebChromeClient.CustomViewCallback() {
-            public void onCustomViewHidden() {
-                playEmbedded();
-            }
-        };
+        private static final WebChromeClient.CustomViewCallback mCallback =
+            new WebChromeClient.CustomViewCallback() {
+                public void onCustomViewHidden() {
+                    // At this point the videoview is pretty much destroyed.
+                    // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
+                    // which happens when the video view is detached from its parent
+                    // view. This happens in the WebChromeClient before this method
+                    // is invoked.
+                    mCurrentProxy.playbackEnded();
+                    mCurrentProxy = null;
+                    mVideoView = null;
+                }
+            };
 
-        // The OnPreparedListener, used to automatically resume
-        // playback when transitioning to/from fullscreen.
-        private MediaPlayer.OnPreparedListener mPreparedListener =
-                new MediaPlayer.OnPreparedListener() {
-            public void onPrepared(MediaPlayer mp) {
-                resumePlayback();
-            }
-        };
-
-        HTML5VideoView(Context context) {
-            super(context);
-        }
-
-        void savePlaybackPosition() {
-            if (isPlaying()) {
-                mPlaybackPosition = getCurrentPosition();
-            }
-        }
-
-        void resumePlayback() {
-            seekTo(mPlaybackPosition);
-            start();
-            setOnPreparedListener(null);
-        }
-
-        void playEmbedded() {
-            // Attach to the WebView.
-            mChildView.attachViewOnUIThread(mEmbeddedLayoutParams);
-            // Make sure we're visible
-            setVisibility(View.VISIBLE);
-            // Set the onPrepared listener so we start
-            // playing when the video view is reattached
-            // and its surface is recreated.
-            setOnPreparedListener(mPreparedListener);
-            mIsFullscreen = false;
-        }
-
-        void playFullScreen() {
-            WebChromeClient client = mWebView.getWebChromeClient();
-            if (client == null) {
+        public static void play(String url, HTML5VideoViewProxy proxy, WebChromeClient client) {
+            if (mCurrentProxy != null) {
+                // Some other video is already playing. Notify the caller that its playback ended.
+                proxy.playbackEnded();
                 return;
             }
-            // Save the current layout params.
-            mEmbeddedLayoutParams =
-                    (AbsoluteLayout.LayoutParams) getLayoutParams();
-            // Detach from the WebView.
-            mChildView.removeViewOnUIThread();
-            // Attach to the browser UI.
-            client.onShowCustomView(this, mCallback);
-            // Set the onPrepared listener so we start
-            // playing when after the video view is reattached
-            // and its surface is recreated.
-            setOnPreparedListener(mPreparedListener);
-            mIsFullscreen = true;
+            mCurrentProxy = proxy;
+            mVideoView = new VideoView(proxy.getContext());
+            mVideoView.setWillNotDraw(false);
+            mVideoView.setMediaController(new MediaController(proxy.getContext()));
+            mVideoView.setVideoURI(Uri.parse(url));
+            mVideoView.start();
+            client.onShowCustomView(mVideoView, mCallback);
         }
+    }
 
-        @Override
-        public boolean onTouchEvent(MotionEvent ev) {
-            // TODO: implement properly (i.e. detect double tap)
-            if (mIsFullscreen || !isPlaying()) {
-                return super.onTouchEvent(ev);
+    // Handler for the messages from WebCore thread to the UI thread.
+    @Override
+    public void handleMessage(Message msg) {
+        // This executes on the UI thread.
+        switch (msg.what) {
+            case INIT: {
+                mPosterView = new ImageView(mWebView.getContext());
+                mChildView.mView = mPosterView;
+                break;
             }
-            playFullScreen();
-            return true;
+            case PLAY: {
+                String url = (String) msg.obj;
+                WebChromeClient client = mWebView.getWebChromeClient();
+                if (client != null) {
+                    VideoPlayer.play(url, this, client);
+                }
+                break;
+            }
+            case SET_POSTER: {
+                Bitmap poster = (Bitmap) msg.obj;
+                mPosterView.setImageBitmap(poster);
+                break;
+            }
+        }
+    }
+
+    public void playbackEnded() {
+        // TODO: notify WebKit
+    }
+
+    // Everything below this comment executes on the WebCore thread, except for
+    // the EventHandler methods, which are called on the network thread.
+
+    // A helper class that knows how to download posters
+    private static final class PosterDownloader implements EventHandler {
+        // The request queue. This is static as we have one queue for all posters.
+        private static RequestQueue mRequestQueue;
+        private static int mQueueRefCount = 0;
+        // The poster URL
+        private String mUrl;
+        // The proxy we're doing this for.
+        private final HTML5VideoViewProxy mProxy;
+        // The poster bytes. We only touch this on the network thread.
+        private ByteArrayOutputStream mPosterBytes;
+        // The request handle. We only touch this on the WebCore thread.
+        private RequestHandle mRequestHandle;
+        // The response status code.
+        private int mStatusCode;
+        // The response headers.
+        private Headers mHeaders;
+        // The handler to handle messages on the WebCore thread.
+        private Handler mHandler;
+
+        public PosterDownloader(String url, HTML5VideoViewProxy proxy) {
+            mUrl = url;
+            mProxy = proxy;
+            mHandler = new Handler();
+        }
+        // Start the download. Called on WebCore thread.
+        public void start() {
+            retainQueue();
+            mRequestHandle = mRequestQueue.queueRequest(mUrl, "GET", null, this, null, 0);
+        }
+        // Cancel the download if active and release the queue. Called on WebCore thread.
+        public void cancelAndReleaseQueue() {
+            if (mRequestHandle != null) {
+                mRequestHandle.cancel();
+                mRequestHandle = null;
+            }
+            releaseQueue();
+        }
+        // EventHandler methods. Executed on the network thread.
+        public void status(int major_version,
+                int minor_version,
+                int code,
+                String reason_phrase) {
+            mStatusCode = code;
         }
 
-        @Override
-        public void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            savePlaybackPosition();
+        public void headers(Headers headers) {
+            mHeaders = headers;
+        }
+
+        public void data(byte[] data, int len) {
+            if (mPosterBytes == null) {
+                mPosterBytes = new ByteArrayOutputStream();
+            }
+            mPosterBytes.write(data, 0, len);
+        }
+
+        public void endData() {
+            if (mStatusCode == 200) {
+                if (mPosterBytes.size() > 0) {
+                    Bitmap poster = BitmapFactory.decodeByteArray(
+                            mPosterBytes.toByteArray(), 0, mPosterBytes.size());
+                    if (poster != null) {
+                        mProxy.doSetPoster(poster);
+                    }
+                }
+                cleanup();
+            } else if (mStatusCode >= 300 && mStatusCode < 400) {
+                // We have a redirect.
+                mUrl = mHeaders.getLocation();
+                if (mUrl != null) {
+                    mHandler.post(new Runnable() {
+                       public void run() {
+                           if (mRequestHandle != null) {
+                               mRequestHandle.setupRedirect(mUrl, mStatusCode,
+                                       new HashMap<String, String>());
+                           }
+                       }
+                    });
+                }
+            }
+        }
+
+        public void certificate(SslCertificate certificate) {
+            // Don't care.
+        }
+
+        public void error(int id, String description) {
+            cleanup();
+        }
+
+        public boolean handleSslErrorRequest(SslError error) {
+            // Don't care. If this happens, data() will never be called so
+            // mPosterBytes will never be created, so no need to call cleanup.
+            return false;
+        }
+        // Tears down the poster bytes stream. Called on network thread.
+        private void cleanup() {
+            if (mPosterBytes != null) {
+                try {
+                    mPosterBytes.close();
+                } catch (IOException ignored) {
+                    // Ignored.
+                } finally {
+                    mPosterBytes = null;
+                }
+            }
+        }
+
+        // Queue management methods. Called on WebCore thread.
+        private void retainQueue() {
+            if (mRequestQueue == null) {
+                mRequestQueue = new RequestQueue(mProxy.getContext());
+            }
+            mQueueRefCount++;
+        }
+
+        private void releaseQueue() {
+            if (mQueueRefCount == 0) {
+                return;
+            }
+            if (--mQueueRefCount == 0) {
+                mRequestQueue.shutdown();
+                mRequestQueue = null;
+            }
         }
     }
 
@@ -159,53 +280,65 @@
         super(Looper.getMainLooper());
         // Save the WebView object.
         mWebView = webView;
+        // create the message handler for this thread
+        createWebCoreHandler();
     }
 
-    @Override
-    public void handleMessage(Message msg) {
-        // This executes on the UI thread.
-        switch (msg.what) {
-            case INIT:
-                // Create the video view and set a default controller.
-                mVideoView = new HTML5VideoView(mWebView.getContext());
-                // This is needed because otherwise there will be a black square
-                // stuck on the screen.
-                mVideoView.setWillNotDraw(false);
-                mVideoView.setMediaController(new MediaController(mWebView.getContext()));
-                mChildView.mView = mVideoView;
-                break;
-            case PLAY:
-                if (mVideoView == null) {
-                    return;
+    private void createWebCoreHandler() {
+        mWebCoreHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    // TODO here we will process the messages from the VideoPlayer
+                    // and will call native WebKit methods.
                 }
-                HashMap<String, Object> map =
-                        (HashMap<String, Object>) msg.obj;
-                String url = (String) map.get("url");
-                mVideoView.setVideoURI(Uri.parse(url));
-                mVideoView.start();
-                break;
-        }
+            }
+        };
     }
 
+    private void doSetPoster(Bitmap poster) {
+        if (poster == null) {
+            return;
+        }
+        // Send the bitmap over to the UI thread.
+        Message message = obtainMessage(SET_POSTER);
+        message.obj = poster;
+        sendMessage(message);
+    }
+
+    public Context getContext() {
+        return mWebView.getContext();
+    }
+
+    // The public methods below are all called from WebKit only.
     /**
      * Play a video stream.
      * @param url is the URL of the video stream.
      * @param webview is the WebViewCore that is requesting the playback.
      */
     public void play(String url) {
+        if (url == null) {
+            return;
+        }
          // We need to know the webview that is requesting the playback.
         Message message = obtainMessage(PLAY);
-        HashMap<String, Object> map = new HashMap();
-        map.put("url", url);
-        message.obj = map;
+        message.obj = url;
         sendMessage(message);
     }
 
+    /**
+     * Create the child view that will cary the poster.
+     */
     public void createView() {
         mChildView = mWebView.mViewManager.createView();
         sendMessage(obtainMessage(INIT));
     }
 
+    /**
+     * Attach the poster view.
+     * @param x, y are the screen coordinates where the poster should be hung.
+     * @param width, height denote the size of the poster.
+     */
     public void attachView(int x, int y, int width, int height) {
         if (mChildView == null) {
             return;
@@ -213,11 +346,36 @@
         mChildView.attachView(x, y, width, height);
     }
 
+    /**
+     * Remove the child view and, thus, the poster.
+     */
     public void removeView() {
         if (mChildView == null) {
             return;
         }
         mChildView.removeView();
+        // This is called by the C++ MediaPlayerPrivate dtor.
+        // Cancel any active poster download.
+        if (mPosterDownloader != null) {
+            mPosterDownloader.cancelAndReleaseQueue();
+        }
+    }
+
+    /**
+     * Load the poster image.
+     * @param url is the URL of the poster image.
+     */
+    public void loadPoster(String url) {
+        if (url == null) {
+            return;
+        }
+        // Cancel any active poster download.
+        if (mPosterDownloader != null) {
+            mPosterDownloader.cancelAndReleaseQueue();
+        }
+        // Load the poster asynchronously
+        mPosterDownloader = new PosterDownloader(url, this);
+        mPosterDownloader.start();
     }
 
     /**
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 4566c4c..953dd92 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1325,7 +1325,7 @@
         final int maxHeight = mPopup.getMaxAvailableHeight(
                 getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
 
-        if (mDropDownAlwaysVisible) {
+        if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.FILL_PARENT) {
             // getMaxAvailableHeight() subtracts the padding, so we put it back,
             // to get the available height for the whole window
             int padding = 0;
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index a185d8d..ba13519 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -133,23 +133,13 @@
     LOGV(__FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
-        DBusError err;
-        dbus_error_init(&err);
 
-        DBusMessage *reply =
-                dbus_func_args_timeout(env, nat->conn, -1, c_path,
-                               "org.bluez.AudioSink", "Connect",
-                                DBUS_TYPE_INVALID);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                                    c_path, "org.bluez.AudioSink", "Connect",
+                                    DBUS_TYPE_INVALID);
+
         env->ReleaseStringUTFChars(path, c_path);
-
-        if (!reply && dbus_error_is_set(&err)) {
-            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
-            return JNI_FALSE;
-        } else if (!reply) {
-            LOGE("DBus reply is NULL in function %s", __FUNCTION__);
-            return JNI_FALSE;
-        }
-        return JNI_TRUE;
+        return ret ? JNI_TRUE : JNI_FALSE;
     }
 #endif
     return JNI_FALSE;
@@ -161,23 +151,13 @@
     LOGV(__FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
-        DBusError err;
-        dbus_error_init(&err);
 
-        DBusMessage *reply =
-              dbus_func_args_timeout(env, nat->conn, -1, c_path,
-                                     "org.bluez.AudioSink", "Disconnect",
-                                     DBUS_TYPE_INVALID);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                                    c_path, "org.bluez.AudioSink", "Disconnect",
+                                    DBUS_TYPE_INVALID);
+
         env->ReleaseStringUTFChars(path, c_path);
-
-        if (!reply && dbus_error_is_set(&err)) {
-            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
-            return JNI_FALSE;
-        } else if (!reply) {
-            LOGE("DBus reply is NULL in function %s", __FUNCTION__);
-            return JNI_FALSE;
-        }
-        return JNI_TRUE;
+        return ret ? JNI_TRUE : JNI_FALSE;
     }
 #endif
     return JNI_FALSE;
diff --git a/core/res/res/drawable-hdpi/ic_emergency.png b/core/res/res/drawable-hdpi/ic_emergency.png
index a2dd372..b4465ff 100644
--- a/core/res/res/drawable-hdpi/ic_emergency.png
+++ b/core/res/res/drawable-hdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index 929d0a2..6dd2949 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -21,7 +21,8 @@
      the user how to unlock their device, or make an emergency call.  This
      is the portrait layout.  -->
 
-<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
@@ -34,31 +35,70 @@
             android:layout_width="0dip"
             android:layout_height="fill_parent"
             android:layout_weight="1.0"
+            android:gravity="center_horizontal"
             >
+        <TextView
+            android:id="@+id/carrier"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            />
+        <TextView
+            android:id="@+id/centerDot"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="5dip"
+            android:layout_marginRight="5dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
+        <TextView
+            android:id="@+id/time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="5dip"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="35sp"
+            />
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_marginTop="-12dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
 
-        <!-- lock icon next to header text -->
-        <LinearLayout
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="3dip"
-                android:gravity="center"
-                >
-            <ImageView android:id="@+id/unlockLockIcon"
-                       android:layout_width="wrap_content"
-                       android:layout_height="wrap_content"
-                       android:layout_marginRight="3dip"
-                       android:baselineAligned="true"
-                       android:gravity="center"
-                       android:src="@android:drawable/ic_lock_idle_lock"
-                    />
 
-            <TextView android:id="@+id/headerText"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:gravity="center"
-                      android:textSize="18sp"/>
-        </LinearLayout>
+        <View
+            android:id="@+id/divider"
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:layout_centerHorizontal="true"
+            android:background="@android:drawable/divider_horizontal_dark"
+                />
+
+        <!-- lock icon and header message -->
+        <TextView
+            android:id="@+id/headerText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dip"
+            android:layout_centerHorizontal="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            android:drawableLeft="@drawable/ic_lock_idle_lock"
+            android:drawablePadding="4dip"
+            android:gravity="center"
+            />
 
 
         <!-- fill space between header and button below -->
@@ -82,7 +122,7 @@
                 <Button android:id="@+id/emergencyCallAlone"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:text="@android:string/lockscreen_emergency_call"
+                    android:text="@string/lockscreen_emergency_call"
                     android:textSize="14sp"
                     android:drawableLeft="@drawable/ic_emergency"
                     android:drawablePadding="8dip"
@@ -105,7 +145,7 @@
                 <Button android:id="@+id/emergencyCallTogether"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:text="@android:string/lockscreen_emergency_call"
+                    android:text="@string/lockscreen_emergency_call"
                     android:textSize="14sp"
                     android:drawableLeft="@drawable/ic_emergency"
                     android:drawablePadding="8dip"
@@ -115,7 +155,7 @@
     </LinearLayout>
 
     <View
-         android:background="@android:drawable/code_lock_left"
+         android:background="@drawable/code_lock_left"
          android:layout_width="2dip"
          android:layout_height="fill_parent" />
 
@@ -124,4 +164,4 @@
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" />
 
-</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index a6c31b6..a5d44fc 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -23,54 +23,93 @@
 <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
-    android:layout_width="wrap_content"
+    android:layout_width="fill_parent"
     android:layout_height="fill_parent"
+    android:gravity="center_horizontal"
     android:background="#A0000000"
         >
 
-    <!-- lock icon and header message -->
     <LinearLayout
+        android:id="@+id/carrierAndDate"
         android:orientation="horizontal"
-        android:layout_width="fill_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1.0"
-        android:gravity="center"
-            >
-
-        <ImageView android:id="@+id/unlockLockIcon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="13dip"
+        >
+        <TextView
+            android:id="@+id/carrier"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginRight="6dip"
-            android:baselineAligned="true"
-            android:gravity="center"
-            android:src="@android:drawable/ic_lock_idle_lock"
-        />
-
-        <TextView android:id="@+id/headerText"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
+        <TextView
+            android:id="@+id/centerDot"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:gravity="center"
-            android:textSize="18sp"/>
+            android:layout_marginLeft="5dip"
+            android:layout_marginRight="5dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
     </LinearLayout>
 
+    <TextView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="-9dip"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textSize="48sp"
+        />
+
     <View
-         android:background="@android:drawable/code_lock_top"
-         android:layout_width="fill_parent"
-         android:layout_height="2dip" />
-    <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
-         android:layout_width="wrap_content"
-         android:layout_height="wrap_content"
+        android:id="@+id/divider"
+        android:layout_width="fill_parent"
+        android:layout_height="1dip"
+        android:layout_marginTop="-4dip"
+        android:layout_centerHorizontal="true"
+        android:background="@android:drawable/divider_horizontal_dark"
+            />
+
+    <!-- lock icon and header message -->
+    <TextView
+        android:id="@+id/headerText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="3dip"
+        android:layout_centerHorizontal="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorSecondary"
+        android:textSize="17sp"
+        android:drawableLeft="@drawable/ic_lock_idle_lock"
+        android:drawablePadding="4dip"
+        />
+
+    <com.android.internal.widget.LockPatternView
+        android:id="@+id/lockPattern"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:layout_marginTop="2dip"
          />
-    <View
-         android:background="@android:drawable/code_lock_bottom"
-         android:layout_width="fill_parent"
-         android:layout_height="8dip" />
 
     <!-- footer -->
     <FrameLayout
         android:layout_width="fill_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1.0"
+        android:layout_height="wrap_content"
         >
 
         <!-- option 1: a single emergency call button -->
@@ -82,8 +121,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_centerInParent="true"
-                android:text="@android:string/lockscreen_emergency_call"
-                android:textSize="14sp"
+                android:text="@string/lockscreen_emergency_call"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:drawableLeft="@drawable/ic_emergency"
                 android:drawablePadding="8dip"
                 />
@@ -105,8 +144,8 @@
                 android:layout_marginBottom="4dip"
                 android:layout_marginLeft="4dip"
                 android:layout_marginRight="2dip"
-                android:text="@android:string/lockscreen_emergency_call"
-                android:textSize="14sp"
+                android:text="@string/lockscreen_emergency_call"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:drawableLeft="@drawable/ic_emergency"
                 android:drawablePadding="8dip"
                 />
@@ -118,7 +157,7 @@
                 android:layout_marginBottom="4dip"
                 android:layout_marginLeft="2dip"
                 android:layout_marginRight="4dip"
-                android:textSize="14sp"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:visibility="invisible"
                 />
         </LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a1a179b..eae838a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -530,6 +530,11 @@
              lines, the IME should provide multiple lines if it can.  Corresponds to
              {@link android.text.InputType#TYPE_TEXT_FLAG_IME_MULTI_LINE}. -->
         <flag name="textImeMultiLine" value="0x00040001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             indicate that the IME should not show any
+             dictionary-based word suggestions.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_NO_SUGGESTIONS}. -->
+        <flag name="textNoSuggestions" value="0x00080001" />
         <!-- Text that will be used as a URI.  Corresponds to
              {@link android.text.InputType#TYPE_CLASS_TEXT} |
              {@link android.text.InputType#TYPE_TEXT_VARIATION_URI}. -->
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 3266f1e..c6f57d4 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -36,7 +36,6 @@
     private Drawable mCurrDrawable;
     private int mAlpha = 0xFF;
     private ColorFilter mColorFilter;
-    private boolean mDither = DEFAULT_DITHER;
 
     private int mCurIndex = -1;
     private boolean mMutated;
@@ -83,10 +82,10 @@
 
     @Override
     public void setDither(boolean dither) {
-        if (mDither != dither) {
-            mDither = dither;
+        if (mDrawableContainerState.mDither != dither) {
+            mDrawableContainerState.mDither = dither;
             if (mCurrDrawable != null) {
-                mCurrDrawable.setDither(mDither);
+                mCurrDrawable.setDither(mDrawableContainerState.mDither);
             }
         }
     }
@@ -212,7 +211,7 @@
             if (d != null) {
                 d.setVisible(isVisible(), true);
                 d.setAlpha(mAlpha);
-                d.setDither(mDither);
+                d.setDither(mDrawableContainerState.mDither);
                 d.setColorFilter(mColorFilter);
                 d.setState(getState());
                 d.setLevel(getLevel());
@@ -285,6 +284,8 @@
         boolean     mCanConstantState;
 
         boolean     mPaddingChecked = false;
+        
+        boolean     mDither = DEFAULT_DITHER;        
 
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
@@ -323,6 +324,8 @@
                 mOpacity = orig.mOpacity;
                 mHaveStateful = orig.mHaveStateful;
                 mStateful = orig.mStateful;
+                
+                mDither = orig.mDither;
 
             } else {
                 mDrawables = new Drawable[10];
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 8b0f154..c02b2e7 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -69,12 +69,6 @@
 
 // ----------------------------------------------------------------------------
 
-struct FlatRegion { // 12 bytes
-    static const unsigned int NUM_RECT_MAX = 1;
-    uint32_t    count;
-    uint16_t    rects[4*NUM_RECT_MAX];
-};
-
 // should be 128 bytes (32 longs)
 class SharedBufferStack
 {
@@ -84,6 +78,18 @@
     friend class SharedBufferServer;
 
 public:
+    struct FlatRegion { // 12 bytes
+        static const unsigned int NUM_RECT_MAX = 1;
+        uint32_t    count;
+        uint16_t    rects[4*NUM_RECT_MAX];
+    };
+    
+    struct Statistics { // 4 longs
+        typedef int32_t usecs_t;
+        usecs_t  totalTime;
+        usecs_t  reserved[3];
+    };
+    
     SharedBufferStack();
     void init(int32_t identity);
     status_t setDirtyRegion(int buffer, const Region& reg);
@@ -100,7 +106,8 @@
     volatile int32_t reallocMask;
 
     int32_t     identity;       // surface's identity (const)
-    int32_t     reserved32[13];
+    int32_t     reserved32[9];
+    Statistics  stats;
     FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
 };
 
@@ -223,7 +230,7 @@
     status_t queue(int buf);
     bool needNewBuffer(int buffer) const;
     status_t setDirtyRegion(int buffer, const Region& reg);
-
+    
 private:
     friend struct Condition;
     friend struct DequeueCondition;
@@ -257,6 +264,8 @@
     };
 
     int32_t tail;
+    // statistics...
+    nsecs_t mDequeueTime[NUM_BUFFER_MAX];
 };
 
 // ----------------------------------------------------------------------------
@@ -275,6 +284,9 @@
     
     Region getDirtyRegion(int buffer) const;
 
+    SharedBufferStack::Statistics getStats() const;
+    
+
 private:
     struct UnlockUpdate : public UpdateBase {
         const int lockedBuffer;
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
index ee80014..9923011 100644
--- a/keystore/java/android/security/ServiceCommand.java
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -49,8 +49,6 @@
 
     public static final int BUFFER_LENGTH = 4096;
 
-    private static final boolean DBG = true;
-
     private String mServiceName;
     private String mTag;
     private InputStream mIn;
@@ -61,7 +59,6 @@
         if (mSocket != null) {
             return true;
         }
-        if (DBG) Log.d(mTag, "connecting...");
         try {
             mSocket = new LocalSocket();
 
@@ -80,7 +77,6 @@
     }
 
     private void disconnect() {
-        if (DBG) Log.d(mTag,"disconnecting...");
         try {
             if (mSocket != null) mSocket.close();
         } catch (IOException ex) { }
diff --git a/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
index 5dc0ba0..1ffbd5b 100644
--- a/libs/surfaceflinger/BlurFilter.cpp
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -111,6 +111,50 @@
     }
 };
 
+template <int FACTOR = 0>
+struct BlurColor888X
+{
+    typedef uint32_t type;
+    int r, g, b;    
+    inline BlurColor888X() { }
+    inline BlurColor888X(uint32_t v) {
+        v = BLUR_RGBA_TO_HOST(v);
+        r = v & 0xFF;
+        g = (v >>  8) & 0xFF;
+        b = (v >> 16) & 0xFF;
+    }
+    inline void clear() { r=g=b=0; }
+    inline uint32_t to(int shift, int last, int dither) const {
+        int R = r;
+        int G = g;
+        int B = b;
+        if  (UNLIKELY(last)) {
+            if (FACTOR>0) {
+                int L = (R+G+G+B)>>2;
+                R += ((L - R) * FACTOR) >> 8;
+                G += ((L - G) * FACTOR) >> 8;
+                B += ((L - B) * FACTOR) >> 8;
+            }
+        }
+        R >>= shift;
+        G >>= shift;
+        B >>= shift;
+        return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R);
+    }    
+    inline BlurColor888X& operator += (const BlurColor888X& rhs) {
+        r += rhs.r;
+        g += rhs.g;
+        b += rhs.b;
+        return *this;
+    }
+    inline BlurColor888X& operator -= (const BlurColor888X& rhs) {
+        r -= rhs.r;
+        g -= rhs.g;
+        b -= rhs.b;
+        return *this;
+    }
+};
+
 struct BlurGray565
 {
     typedef uint16_t type;
@@ -316,7 +360,13 @@
         int kernelSizeUser,
         int repeat)
 {
-    return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+    status_t err = BAD_VALUE;
+    if (image->format == GGL_PIXEL_FORMAT_RGB_565) {
+        err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+    } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) {
+        err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat);
+    }
+    return err;
 }
 
 } // namespace android
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index d893f0a..cc913cbd 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -174,6 +174,13 @@
 
     surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
 
+    if (mFlags & UPDATE_ON_DEMAND) {
+        // if we have update on demand, we definitely don't need to
+        // preserve the backbuffer, which is usually costly.
+        eglSurfaceAttrib(display, surface,
+                EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
+    }
+
     if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
         if (dummy == EGL_BUFFER_PRESERVED) {
             mFlags |= BUFFER_PRESERVED;
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 1e7f1e6..7387c85 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -303,7 +303,6 @@
 
     // Index of the back buffer
     const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
-
     if (backbufferChanged) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
@@ -318,17 +317,6 @@
         // buffer, it'll get the new size.
         setDrawingSize(temp.w, temp.h);
 
-        // all buffers need reallocation
-        lcblk->reallocate();
-
-        // recompute the visible region
-        // FIXME: ideally we would do that only when we have received
-        // a buffer of the right size
-        flags |= Layer::eVisibleRegion;
-        this->contentDirty = true;
-        
-#if 0 
-        // FIXME: handle freeze lock
         // we're being resized and there is a freeze display request,
         // acquire a freeze lock, so that the screen stays put
         // until we've redrawn at the new size; this is to avoid
@@ -340,7 +328,12 @@
                 mFreezeLock = mFlinger->getFreezeLock();
             }
         }
-#endif
+
+        // recompute the visible region
+        flags |= Layer::eVisibleRegion;
+        this->contentDirty = true;
+        // all buffers need reallocation
+        lcblk->reallocate();
     }
 
     if (temp.sequence != front.sequence) {
@@ -382,6 +375,13 @@
     const Region dirty(lcblk->getDirtyRegion(buf));
     mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
 
+
+    const Layer::State& front(drawingState());
+    if (newFrontBuffer->getWidth() == front.w &&
+        newFrontBuffer->getHeight() ==front.h) {
+        mFreezeLock.clear();
+    }
+
     // FIXME: signal an event if we have more buffers waiting
     // mFlinger->signalEvent();
 
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index e14f35b..0ef663f 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -40,9 +40,9 @@
 
 LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-     : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
-     mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
-     mWidthScale(1.0f), mHeightScale(1.0f)
+: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
+mWidthScale(1.0f), mHeightScale(1.0f)
 {
 }
 
@@ -136,6 +136,13 @@
         // create the texture name the first time
         // can't do that in the ctor, because it runs in another thread.
         glGenTextures(1, &mTextureName);
+        glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat);
+        glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType);
+        if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) {
+            mReadFormat = GL_RGBA;
+            mReadType = GL_UNSIGNED_BYTE;
+            mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+        }
     }
 
     Region::const_iterator it = clip.begin();
@@ -143,33 +150,39 @@
     if (it != end) {
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mTextureName);
-    
+
         if (mRefreshCache) {
             mRefreshCache = false;
             mAutoRefreshPending = false;
-            
-            // allocate enough memory for 4-bytes (2 pixels) aligned data
-            const int32_t s = (w + 1) & ~1;
-            uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
+
+            int32_t pixelSize = 4;
+            int32_t s = w;
+            if (mReadType == GL_UNSIGNED_SHORT_5_6_5) {
+                // allocate enough memory for 4-bytes (2 pixels) aligned data
+                s = (w + 1) & ~1;
+                pixelSize = 2;
+            }
+
+            uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize);
 
             // This reads the frame-buffer, so a h/w GL would have to
             // finish() its rendering first. we don't want to do that
             // too often. Read data is 4-bytes aligned.
-            glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
-            
+            glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels);
+
             // blur that texture.
             GGLSurface bl;
             bl.version = sizeof(GGLSurface);
             bl.width = w;
             bl.height = h;
             bl.stride = s;
-            bl.format = GGL_PIXEL_FORMAT_RGB_565;
+            bl.format = mBlurFormat;
             bl.data = (GGLubyte*)pixels;            
             blurFilter(&bl, 8, 2);
 
             if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
+                        mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / w;
                 mHeightScale =-1.0f / h;
                 mYOffset = 0;
@@ -178,10 +191,10 @@
                 GLuint th = 1 << (31 - clz(h));
                 if (tw < w) tw <<= 1;
                 if (th < h) th <<= 1;
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0,
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
+                glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0,
+                        mReadFormat, mReadType, NULL);
                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, 
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                        mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / tw;
                 mHeightScale =-1.0f / th;
                 mYOffset = th-h;
@@ -189,7 +202,7 @@
 
             free((void*)pixels);
         }
-        
+
         const State& s = drawingState();
         if (UNLIKELY(s.alpha < 0xFF)) {
             const GGLfixed alpha = (s.alpha << 16)/255;
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index bf36ae4..2e9d7c6 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -59,6 +59,9 @@
     mutable GLfloat mWidthScale;
     mutable GLfloat mHeightScale;
     mutable GLfloat mYOffset;
+    mutable GLint   mReadFormat;
+    mutable GLint   mReadType;
+    mutable uint32_t mBlurFormat;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 38a897d..667571b 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -595,6 +595,7 @@
 
     *overlayRef = new OverlayRef(mOverlayHandle, channel,
             mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
+    mLayer.mFlinger->signalEvent();
 }
 
 LayerBuffer::OverlaySource::~OverlaySource()
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index a352431..31b5128c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1521,6 +1521,7 @@
             /*** Layer ***/
             sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
             if (l != 0) {
+                SharedBufferStack::Statistics stats = l->lcblk->getStats();
                 result.append( l->lcblk->dump("      ") );
                 sp<const Buffer> buf0(l->getBuffer(0));
                 sp<const Buffer> buf1(l->getBuffer(1));
@@ -1539,10 +1540,10 @@
                 snprintf(buffer, SIZE,
                         "      "
                         "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
-                        " freezeLock=%p\n",
+                        " freezeLock=%p, dq-q-time=%u us\n",
                         l->pixelFormat(),
                         w0, h0, s0, w1, h1, s1,
-                        l->getFreezeLock().get());
+                        l->getFreezeLock().get(), stats.totalTime);
                 result.append(buffer);
                 buffer[0] = 0;
             }
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
index 7789a3f..9ad4349 100644
--- a/libs/ui/SharedBufferStack.cpp
+++ b/libs/ui/SharedBufferStack.cpp
@@ -276,6 +276,8 @@
         LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
                 tail, stack.head, stack.available, stack.queued);
     }
+        
+    const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
 
     //LOGD("[%d] about to dequeue a buffer",
     //        mSharedStack->identity);
@@ -296,6 +298,8 @@
     LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
             dequeued, tail, dump("").string());
 
+    mDequeueTime[dequeued] = dequeueTime; 
+
     return dequeued;
 }
 
@@ -312,7 +316,7 @@
 status_t SharedBufferClient::lock(int buf)
 {
     LockCondition condition(this, buf);
-    status_t err = waitForCondition(condition);    
+    status_t err = waitForCondition(condition);
     return err;
 }
 
@@ -321,6 +325,9 @@
     QueueUpdate update(this);
     status_t err = updateCondition( update );
     LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
+    SharedBufferStack& stack( *mSharedStack );
+    const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
+    stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
     return err;
 }
 
@@ -393,5 +400,12 @@
     return stack.getDirtyRegion(buffer);
 }
 
+SharedBufferStack::Statistics SharedBufferServer::getStats() const
+{
+    SharedBufferStack& stack( *mSharedStack );
+    return stack.stats;
+}
+
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index 69e93a1..10796f1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -16,6 +16,7 @@
 
 package com.android.mediaframeworktest.stress;
 
+
 import com.android.mediaframeworktest.MediaFrameworkTest;
 
 import java.io.BufferedWriter;
@@ -26,6 +27,7 @@
 import android.hardware.Camera;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
+import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
@@ -54,7 +56,14 @@
     private static final String OUTPUT_FILE_EXT = ".3gp";
     private static final String MEDIA_STRESS_OUTPUT =
         "/sdcard/mediaStressOutput.txt";
-    
+    private Looper mCameraLooper = null;
+    private Looper mRecorderLooper = null;
+    private final Object lock = new Object();
+    private final Object recorderlock = new Object();
+    private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000;  // Milliseconds.
+    private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback();
+    private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback();
+
     public MediaRecorderStressTest() {
         super("com.android.mediaframeworktest", MediaFrameworkTest.class);
     }
@@ -63,41 +72,129 @@
         getActivity();
         super.setUp();      
     }
-       
+
+    private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback {
+        public void onError(int error, android.hardware.Camera camera) {
+            if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
+                assertTrue("Camera test mediaserver died", false);
+            }
+        }
+    }
+
+    private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener {
+        public void onError(MediaRecorder mr, int what, int extra) {
+            // fail the test case no matter what error come up
+            assertTrue("mediaRecorder error", false);
+        }
+    }
+
+    private void initializeCameraMessageLooper() {
+        Log.v(TAG, "start looper");
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by camera.
+                Looper.prepare();
+                Log.v(TAG, "start loopRun");
+                mCameraLooper = Looper.myLooper();
+                mCamera = Camera.open();
+                synchronized (lock) {
+                    lock.notify();
+                }
+                Looper.loop();
+                Log.v(TAG, "initializeMessageLooper: quit.");
+            }
+        }.start();
+    }
+
+    private void initializeRecorderMessageLooper() {
+        Log.v(TAG, "start looper");
+        new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                Log.v(TAG, "start loopRun");
+                mRecorderLooper = Looper.myLooper();
+                mRecorder = new MediaRecorder();
+                synchronized (recorderlock) {
+                    recorderlock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+                Log.v(TAG, "initializeMessageLooper: quit.");
+            }
+        }.start();
+    }
+
+    /*
+     * Terminates the message looper thread.
+     */
+    private void terminateCameraMessageLooper() {
+        mCameraLooper.quit();
+        try {
+            Thread.sleep(1000);
+        } catch (Exception e){
+            Log.v(TAG, e.toString());
+        }
+        mCamera.release();
+    }
+
+    /*
+     * Terminates the message looper thread.
+     */
+    private void terminateRecorderMessageLooper() {
+        mRecorderLooper.quit();
+        try {
+            Thread.sleep(1000);
+        } catch (Exception e){
+            Log.v(TAG, e.toString());
+        }
+        mRecorder.release();
+    }
+
     //Test case for stressing the camera preview.
     @LargeTest
     public void testStressCamera() throws Exception {
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
         output.write("Camera start preview stress:\n");
-        output.write("Total number of loops:" + 
+        output.write("Total number of loops:" +
                 NUMBER_OF_CAMERA_STRESS_LOOPS + "\n");
-        try {        
+        try {
             Log.v(TAG, "Start preview");
             output.write("No of loop: ");
+
             for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++){
-                mCamera = Camera.open();
+                synchronized (lock) {
+                    initializeCameraMessageLooper();
+                    try {
+                        lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mCamera.setErrorCallback(mCameraErrorCallback);
                 mCamera.setPreviewDisplay(mSurfaceHolder);
                 mCamera.startPreview();
                 Thread.sleep(WAIT_TIME_CAMERA_TEST);
                 mCamera.stopPreview();
-                mCamera.release();
+                terminateCameraMessageLooper();
                 output.write(" ," + i);
             }
         } catch (Exception e) {
-                Log.v(TAG, e.toString());
+            assertTrue("CameraStressTest", false);
+            Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
     }
-    
+
     //Test case for stressing the camera preview.
     @LargeTest
     public void testStressRecorder() throws Exception {
         String filename;
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
@@ -108,12 +205,20 @@
             output.write("No of loop: ");
             Log.v(TAG, "Start preview");
             for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++){
+                synchronized (recorderlock) {
+                    initializeRecorderMessageLooper();
+                    try {
+                        recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
                 Log.v(TAG, "counter = " + i);
                 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
                 Log.v(TAG, filename);
-                mRecorder = new MediaRecorder();
+                mRecorder.setOnErrorListener(mRecorderErrorCallback);
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);          
+                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
                 mRecorder.setVideoFrameRate(20);
                 mRecorder.setVideoSize(176,144);
@@ -125,47 +230,63 @@
                 Log.v(TAG, "prepare");
                 mRecorder.prepare();
                 Log.v(TAG, "before release");
-                Thread.sleep(WAIT_TIME_RECORDER_TEST);  
+                Thread.sleep(WAIT_TIME_RECORDER_TEST);
                 mRecorder.reset();
-                mRecorder.release();
+                terminateRecorderMessageLooper();
                 output.write(", " + i);
             }
         } catch (Exception e) {
-                Log.v(TAG, e.toString());
+            assertTrue("Recorder Stress test", false);
+            Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
     }
-    
-    
+
     //Stress test case for switching camera and video recorder preview.
     @LargeTest
     public void testStressCameraSwitchRecorder() throws Exception {
         String filename;
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
         output.write("Camera and video recorder preview switching\n");
         output.write("Total number of loops:"
                 + NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n");
-        try {    
+        try {
             Log.v(TAG, "Start preview");
             output.write("No of loop: ");
             for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++){
-                mCamera = Camera.open();
+                synchronized (lock) {
+                    initializeCameraMessageLooper();
+                    try {
+                        lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mCamera.setErrorCallback(mCameraErrorCallback);
                 mCamera.setPreviewDisplay(mSurfaceHolder);
                 mCamera.startPreview();
                 Thread.sleep(WAIT_TIME_CAMERA_TEST);
                 mCamera.stopPreview();
-                mCamera.release();
+                terminateCameraMessageLooper();
                 mCamera = null;
                 Log.v(TAG, "release camera");
                 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
                 Log.v(TAG, filename);
-                mRecorder = new MediaRecorder();
+                synchronized (recorderlock) {
+                    initializeRecorderMessageLooper();
+                    try {
+                        recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mRecorder.setOnErrorListener(mRecorderErrorCallback);
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);          
+                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
                 mRecorder.setVideoFrameRate(20);
                 mRecorder.setVideoSize(176,144);
@@ -176,23 +297,24 @@
                 Log.v(TAG, "prepare");
                 mRecorder.prepare();
                 Log.v(TAG, "before release");
-                Thread.sleep(WAIT_TIME_CAMERA_TEST);  
-                mRecorder.release();
+                Thread.sleep(WAIT_TIME_CAMERA_TEST);
+                terminateRecorderMessageLooper();
                 Log.v(TAG, "release video recorder");
                 output.write(", " + i);
             }
         } catch (Exception e) {
+            assertTrue("Camer and recorder switch mode", false);
                 Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
     }
-    
+
     //Stress test case for record a video and play right away.
     @LargeTest
     public void testStressRecordVideoAndPlayback() throws Exception {
         String filename;
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
@@ -204,10 +326,18 @@
             for (int i = 0; i < NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS; i++){
                 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
                 Log.v(TAG, filename);
-                mRecorder = new MediaRecorder();
+                synchronized (recorderlock) {
+                    initializeRecorderMessageLooper();
+                    try {
+                        recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mRecorder.setOnErrorListener(mRecorderErrorCallback);
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);          
+                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
                 mRecorder.setVideoFrameRate(20);
                 mRecorder.setVideoSize(352,288);
@@ -216,11 +346,11 @@
                 Log.v(TAG, "mediaRecorder setPreview");
                 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
                 mRecorder.prepare();
-                mRecorder.start();               
+                mRecorder.start();
                 Thread.sleep(WAIT_TIME_RECORD);
                 Log.v(TAG, "Before stop");
                 mRecorder.stop();
-                mRecorder.release();
+                terminateRecorderMessageLooper();
                 //start the playback
                 MediaPlayer mp = new MediaPlayer();
                 mp.setDataSource(filename);
@@ -232,10 +362,10 @@
                 output.write(", " + i);
             }
         } catch (Exception e) {
+            assertTrue("record and playback", false);
                 Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
-    }   
+    }
 }
-
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 0e60dd6..c6be61d 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -649,11 +649,21 @@
         int N = packages.size();
         for (int a = N-1; a >= 0; a--) {
             PackageInfo pkg = packages.get(a);
-            ApplicationInfo app = pkg.applicationInfo;
-            if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
-                    || app.backupAgentName == null
-                    || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
-                            pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
+            try {
+                ApplicationInfo app = pkg.applicationInfo;
+                if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
+                        || app.backupAgentName == null
+                        || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+                                pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
+                    packages.remove(a);
+                }
+                else {
+                    // we will need the shared library path, so look that up and store it here
+                    app = mPackageManager.getApplicationInfo(pkg.packageName,
+                            PackageManager.GET_SHARED_LIBRARY_FILES);
+                    pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
+                }
+            } catch (NameNotFoundException e) {
                 packages.remove(a);
             }
         }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 60496d6..d53f002 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7056,7 +7056,7 @@
                         + " attHidden=" + mAttachedHidden
                         + " tok.hiddenRequested="
                         + (mAppToken != null ? mAppToken.hiddenRequested : false)
-                        + " tok.idden="
+                        + " tok.hidden="
                         + (mAppToken != null ? mAppToken.hidden : false)
                         + " animating=" + mAnimating
                         + " tok animating="
@@ -7085,10 +7085,20 @@
                 if (mAttrs.type != TYPE_APPLICATION_STARTING
                         && mAppToken != null) {
                     mAppToken.firstWindowDrawn = true;
-                    if (mAnimation == null && mAppToken.startingData != null) {
+                    
+                    if (mAppToken.startingData != null) {
                         if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
                                 + mToken
                                 + ": first real window is shown, no animation");
+                        // If this initial window is animating, stop it -- we
+                        // will do an animation to reveal it from behind the
+                        // starting window, so there is no need for it to also
+                        // be doing its own stuff.
+                        if (mAnimation != null) {
+                            mAnimation = null;
+                            // Make sure we clean up the animation.
+                            mAnimating = true;
+                        }
                         mFinishedStarting.add(mAppToken);
                         mH.sendEmptyMessage(H.FINISHED_STARTING);
                     }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
index c62f94f..f2025c6 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
@@ -36,8 +36,11 @@
     public void testHandlerThread() throws Exception {
         HandlerThread th1 =  new HandlerThread("HandlerThreadTest") {
             protected void onLooperPrepared() {
-                mDidSetup = true;
-                mLooperTid = Process.myTid();
+                synchronized (HandlerThreadTest.this) {
+                    mDidSetup = true;
+                    mLooperTid = Process.myTid();
+                    HandlerThreadTest.this.notify();
+                }
             }
         };
         
@@ -49,14 +52,23 @@
         assertTrue(th1.isAlive());
         assertNotNull(th1.getLooper());
        
-        /* 
-         * Since getLooper() will block until the HandlerThread is setup, we are guaranteed
-         * that mDidSetup and mLooperTid will have been initalized. If they have not, then 
-         * this test should fail
-         */
+        // The call to getLooper() internally blocks until the looper is
+        // available, but will call onLooperPrepared() after that.  So we
+        // need to block here to wait for our onLooperPrepared() to complete
+        // and fill in the values we expect.
+        synchronized (this) {
+            while (!mDidSetup) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        
+        // Make sure that the process was set.
+        assertNotSame(-1, mLooperTid);
         // Make sure that the onLooperPrepared() was called on a different thread.
         assertNotSame(Process.myTid(), mLooperTid);
-        assertTrue(mDidSetup);
         
         final Handler h1 = new Handler(th1.getLooper()) {
             public void handleMessage(Message msg) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 074d90f..3fef61c 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -291,13 +291,20 @@
     }
 
     public void finished() {
-        if (mUiAutoTestPath != null) {
-            //don't really finish here
-            moveToNextTest();
-        } else {
-            if (mCallback != null) {
-                mCallback.finished();
+        if (mTestPageLoaded) {
+            if (mUiAutoTestPath != null) {
+                //don't really finish here
+                moveToNextTest();
+            } else {
+                if (mCallback != null) {
+                    mCallback.finished();
+                }
             }
+        } else {
+            // The test is complete but the page has not completed loading. We
+            // can't continue to the next test until both the test is finished
+            // and the page has stopped loading.
+            mReadyForNextTest = true;
         }
     }
 
@@ -445,12 +452,14 @@
         @Override
         public void onPageFinished(WebView view, String url) {
             Log.v(LOGTAG, "onPageFinished, url=" + url);
+            mTestPageLoaded = true;
             super.onPageFinished(view, url);
         }
 
         @Override
         public void onPageStarted(WebView view, String url, Bitmap favicon) {
             Log.v(LOGTAG, "onPageStarted, url=" + url);
+            mTestPageLoaded = false;
             super.onPageStarted(view, url, favicon);
         }
 
@@ -480,6 +489,17 @@
         @Override
         public void onProgressChanged(WebView view, int newProgress) {
             if (newProgress == 100) {
+
+                if (mReadyForNextTest) {
+                    // In this case, the test has completed (i.e. called
+                    // layoutTestController.notifyDone) before the page finished loading. This
+                    // usually happens if the test is not invoked by an onload handler, rather
+                    // directly in a script tag. Now that the page has finished loading, it is
+                    // safe for DRT to go to the next test.
+                    finished();
+                    return;
+                }
+
                 if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
                     String url = mWebView.getUrl();
                     Log.v(LOGTAG, "Finished: "+ url);
@@ -655,6 +675,8 @@
         mDumpDatabaseCallbacks = false;
         mCanOpenWindows = false;
         mEventSender.resetMouse();
+        mTestPageLoaded = false;
+        mReadyForNextTest = false;
     }
 
     private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
@@ -711,6 +733,9 @@
     private StringBuffer mConsoleMessages;
     private boolean mCanOpenWindows;
 
+    private boolean mTestPageLoaded = false;
+    private boolean mReadyForNextTest = false;
+
     static final String TIMEOUT_STR = "**Test timeout";
 
     static final int MSG_TIMEOUT = 0;
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 9a11404..e3d8bf4 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -1350,7 +1350,7 @@
      */
     private synchronized void requestPolledInfo(WifiInfo info, boolean polling)
     {
-        int newRssi = WifiNative.getRssiCommand();
+        int newRssi = (polling ? WifiNative.getRssiApproxCommand() : WifiNative.getRssiCommand());
         if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
             /* some implementations avoid negative values by adding 256
              * so we need to adjust for that here.