Merge change 25100 into eclair

* changes:
  Implement Object readback.
diff --git a/api/current.xml b/api/current.xml
index f8cf61f..7562f2e 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -6825,7 +6825,7 @@
  value="16843221"
  static="true"
  final="true"
- deprecated="deprecated"
+ deprecated="not deprecated"
  visibility="public"
 >
 </field>
@@ -16089,6 +16089,17 @@
  visibility="public"
 >
 </method>
+<method name="onBackPressed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onChildTitleChanged"
  return="void"
  abstract="false"
@@ -16318,6 +16329,21 @@
 <parameter name="event" type="android.view.KeyEvent">
 </parameter>
 </method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
 <method name="onKeyMultiple"
  return="boolean"
  abstract="false"
@@ -20085,6 +20111,17 @@
  visibility="public"
 >
 </method>
+<method name="onBackPressed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onContentChanged"
  return="void"
  abstract="false"
@@ -20219,6 +20256,21 @@
 <parameter name="event" type="android.view.KeyEvent">
 </parameter>
 </method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
 <method name="onKeyMultiple"
  return="boolean"
  abstract="false"
@@ -24714,6 +24766,17 @@
  visibility="public"
 >
 </method>
+<method name="getFastDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getInstance"
  return="android.app.WallpaperManager"
  abstract="false"
@@ -24738,6 +24801,17 @@
  visibility="public"
 >
 </method>
+<method name="peekFastDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="setBitmap"
  return="void"
  abstract="false"
@@ -63330,7 +63404,7 @@
  type="android.graphics.drawable.BitmapDrawable"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="filepath" type="java.lang.String">
@@ -63343,6 +63417,30 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="filepath" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
 <parameter name="is" type="java.io.InputStream">
 </parameter>
 </constructor>
@@ -64521,6 +64619,19 @@
  visibility="public"
 >
 </method>
+<method name="newDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+</method>
 </class>
 <class name="DrawableContainer"
  extends="android.graphics.drawable.Drawable"
@@ -69511,6 +69622,17 @@
  visibility="public"
 >
 </constructor>
+<method name="getKeyDispatcherState"
+ return="android.view.KeyEvent.DispatcherState"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onBind"
  return="android.os.IBinder"
  abstract="false"
@@ -70256,6 +70378,21 @@
 <parameter name="event" type="android.view.KeyEvent">
 </parameter>
 </method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
 <method name="onKeyMultiple"
  return="boolean"
  abstract="false"
@@ -101558,6 +101695,17 @@
  visibility="protected"
 >
 </method>
+<method name="quit"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <interface name="IBinder"
  abstract="true"
@@ -144753,7 +144901,7 @@
  type="android.view.KeyEvent"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="origEvent" type="android.view.KeyEvent">
@@ -144810,6 +144958,25 @@
 <parameter name="newRepeat" type="int">
 </parameter>
 </method>
+<method name="changeTimeRepeat"
+ return="android.view.KeyEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+<parameter name="eventTime" type="long">
+</parameter>
+<parameter name="newRepeat" type="int">
+</parameter>
+<parameter name="newFlags" type="int">
+</parameter>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -144828,11 +144995,28 @@
  synchronized="false"
  static="false"
  final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="receiver" type="android.view.KeyEvent.Callback">
+</parameter>
+</method>
+<method name="dispatch"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 <parameter name="receiver" type="android.view.KeyEvent.Callback">
 </parameter>
+<parameter name="state" type="android.view.KeyEvent.DispatcherState">
+</parameter>
+<parameter name="target" type="java.lang.Object">
+</parameter>
 </method>
 <method name="getAction"
  return="int"
@@ -145079,6 +145263,17 @@
  visibility="public"
 >
 </method>
+<method name="isLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isModifierKey"
  return="boolean"
  abstract="false"
@@ -145136,6 +145331,28 @@
  visibility="public"
 >
 </method>
+<method name="isTracking"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="startTracking"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="writeToParcel"
  return="void"
  abstract="false"
@@ -145205,6 +145422,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_CANCELED_LONG_PRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_EDITOR_ACTION"
  type="int"
  transient="false"
@@ -145238,6 +145466,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_LONG_PRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_SOFT_KEYBOARD"
  type="int"
  transient="false"
@@ -145249,6 +145488,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_TRACKING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_VIRTUAL_HARD_KEY"
  type="int"
  transient="false"
@@ -146394,6 +146644,21 @@
 <parameter name="event" type="android.view.KeyEvent">
 </parameter>
 </method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
 <method name="onKeyMultiple"
  return="boolean"
  abstract="true"
@@ -146427,6 +146692,101 @@
 </parameter>
 </method>
 </interface>
+<class name="KeyEvent.DispatcherState"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="KeyEvent.DispatcherState"
+ type="android.view.KeyEvent.DispatcherState"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="handleUpEvent"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="isTracking"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="performedLongPress"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="reset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="reset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="java.lang.Object">
+</parameter>
+</method>
+<method name="startTracking"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+<parameter name="target" type="java.lang.Object">
+</parameter>
+</method>
+</class>
 <class name="LayoutInflater"
  extends="java.lang.Object"
  abstract="true"
@@ -149719,6 +150079,19 @@
  visibility="public"
 >
 </method>
+<method name="setOnTop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="onTop" type="boolean">
+</parameter>
+</method>
 </class>
 <class name="TouchDelegate"
  extends="java.lang.Object"
@@ -150801,6 +151174,17 @@
  visibility="public"
 >
 </method>
+<method name="getKeyDispatcherState"
+ return="android.view.KeyEvent.DispatcherState"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getLayoutParams"
  return="android.view.ViewGroup.LayoutParams"
  abstract="false"
@@ -151927,6 +152311,21 @@
 <parameter name="event" type="android.view.KeyEvent">
 </parameter>
 </method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
 <method name="onKeyMultiple"
  return="boolean"
  abstract="false"
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index 24496bb..35f4846 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -265,6 +265,11 @@
     return NO_ERROR;
 }
 
+status_t CameraHardwareStub::cancelAutoFocus()
+{
+    return NO_ERROR;
+}
+
 /*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
 {
     CameraHardwareStub *c = (CameraHardwareStub *)cookie;
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 000906a..f957fa8 100644
--- a/camera/libcameraservice/CameraHardwareStub.h
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -51,6 +51,7 @@
     virtual void        releaseRecordingFrame(const sp<IMemory>& mem);
 
     virtual status_t    autoFocus();
+    virtual status_t    cancelAutoFocus();
     virtual status_t    takePicture();
     virtual status_t    cancelPicture();
     virtual status_t    dump(int fd, const Vector<String16>& args) const;
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index f425f6b..bab7d08 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -798,7 +798,6 @@
 }
 #endif
 
-// take a picture - image is returned in callback
 status_t CameraService::Client::autoFocus()
 {
     LOGD("autoFocus (pid %d)", getCallingPid());
@@ -815,6 +814,22 @@
     return mHardware->autoFocus();
 }
 
+status_t CameraService::Client::cancelAutoFocus()
+{
+    LOGD("cancelAutoFocus (pid %d)", getCallingPid());
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return INVALID_OPERATION;
+    }
+
+    return mHardware->cancelAutoFocus();
+}
+
 // take a picture - image is returned in callback
 status_t CameraService::Client::takePicture()
 {
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index f8c7216..0a909cf 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -110,6 +110,9 @@
         // auto focus
         virtual status_t        autoFocus();
 
+        // cancel auto focus
+        virtual status_t        cancelAutoFocus();
+
         // take a picture - returns an IMemory (ref-counted mmap)
         virtual status_t        takePicture();
 
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 6abed93..c13893a 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1445,13 +1445,18 @@
                             intent.getComponent().getClassName())) {
                 createNoCredentialsPermissionNotification(account, intent);
             } else {
+                final Integer notificationId = getSigninRequiredNotificationId(account);
+                intent.addCategory(String.valueOf(notificationId));
                 Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
                         0 /* when */);
-                n.setLatestEventInfo(mContext, mContext.getText(R.string.notification_title),
+                final String notificationTitleFormat =
+                        mContext.getText(R.string.notification_title).toString();
+                n.setLatestEventInfo(mContext,
+                        String.format(notificationTitleFormat, account.name),
                         message, PendingIntent.getActivity(
                         mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
                 ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
-                        .notify(getSigninRequiredNotificationId(account), n);
+                        .notify(notificationId, n);
             }
         } finally {
             restoreCallingIdentity(identityToken);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8c10091..545db17 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -34,6 +34,7 @@
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1752,8 +1753,17 @@
      * 
      * <p>If the focused view didn't want this event, this method is called.
      *
-     * <p>The default implementation handles KEYCODE_BACK to stop the activity
-     * and go back, and other default key handling if configured with {@link #setDefaultKeyMode}.
+     * <p>The default implementation takes care of {@link KeyEvent#KEYCODE_BACK}
+     * by calling {@link #onBackPressed()}, though the behavior varies based
+     * on the application compatibility mode: for
+     * {@link android.os.Build.VERSION_CODES#ECLAIR} or later applications,
+     * it will set up the dispatch to call {@link #onKeyUp} where the action
+     * will be performed; for earlier applications, it will perform the
+     * action immediately in on-down, as those versions of the platform
+     * behaved.
+     * 
+     * <p>Other additional default key handling may be performed
+     * if configured with {@link #setDefaultKeyMode}.
      * 
      * @return Return <code>true</code> to prevent this event from being propagated
      * further, or <code>false</code> to indicate that you have not handled 
@@ -1762,16 +1772,24 @@
      * @see android.view.KeyEvent
      */
     public boolean onKeyDown(int keyCode, KeyEvent event)  {
-        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
-            finish();
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            if (getApplicationInfo().targetSdkVersion
+                    >= Build.VERSION_CODES.ECLAIR) {
+                event.startTracking();
+            } else {
+                onBackPressed();
+            }
             return true;
         }
         
         if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
             return false;
         } else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
-            return getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL, 
-                                                    keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE);
+            if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL, 
+                    keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
+                return true;
+            }
+            return false;
         } else {
             // Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*
             boolean clearSpannable = false;
@@ -1780,8 +1798,8 @@
                 clearSpannable = true;
                 handled = false;
             } else {
-                handled = TextKeyListener.getInstance().onKeyDown(null, mDefaultKeySsb, 
-                                                                  keyCode, event);
+                handled = TextKeyListener.getInstance().onKeyDown(
+                        null, mDefaultKeySsb, keyCode, event);
                 if (handled && mDefaultKeySsb.length() > 0) {
                     // something useable has been typed - dispatch it now.
 
@@ -1813,11 +1831,23 @@
     }
 
     /**
+     * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+     * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+     * the event).
+     */
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    /**
      * Called when a key was released and not handled by any of the views
      * inside of the activity. So, for example, key presses while the cursor 
      * is inside a TextView will not trigger the event (unless it is a navigation
      * to another object) because TextView handles its own key presses.
      * 
+     * <p>The default implementation handles KEYCODE_BACK to stop the activity
+     * and go back.
+     * 
      * @return Return <code>true</code> to prevent this event from being propagated
      * further, or <code>false</code> to indicate that you have not handled 
      * this event and it should continue to be propagated. 
@@ -1825,6 +1855,14 @@
      * @see KeyEvent
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (getApplicationInfo().targetSdkVersion
+                >= Build.VERSION_CODES.ECLAIR) {
+            if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+                    && !event.isCanceled()) {
+                onBackPressed();
+                return true;
+            }
+        }
         return false;
     }
 
@@ -1838,6 +1876,15 @@
     }
     
     /**
+     * Called when the activity has detected the user's press of the back
+     * key.  The default implementation simply finishes the current activity,
+     * but you can override this to do whatever you want.
+     */
+    public void onBackPressed() {
+        finish();
+    }
+    
+    /**
      * Called when a touch screen event was not handled by any of the views
      * under it.  This is most useful to process touch events that happen
      * outside of your window bounds, where there is no view to receive it.
@@ -1909,9 +1956,10 @@
     /**
      * Called when the current {@link Window} of the activity gains or loses
      * focus.  This is the best indicator of whether this activity is visible
-     * to the user.
+     * to the user.  The default implementation clears the key tracking
+     * state, so should always be called.
      * 
-     * <p>Note that this provides information what global focus state, which
+     * <p>Note that this provides information about global focus state, which
      * is managed independently of activity lifecycles.  As such, while focus
      * changes will generally have some relation to lifecycle changes (an
      * activity that is stopped will not generally get window focus), you
@@ -1985,10 +2033,14 @@
      */
     public boolean dispatchKeyEvent(KeyEvent event) {
         onUserInteraction();
-        if (getWindow().superDispatchKeyEvent(event)) {
+        Window win = getWindow();
+        if (win.superDispatchKeyEvent(event)) {
             return true;
         }
-        return event.dispatch(this);
+        View decor = mDecor;
+        if (decor == null) decor = win.getDecorView();
+        return event.dispatch(this, decor != null
+                ? decor.getKeyDispatcherState() : null, this);
     }
 
     /**
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 1b96af9..58e8b32 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -481,17 +481,15 @@
      * 
      * <p>If the focused view didn't want this event, this method is called.
      *
-     * <p>The default implementation handles KEYCODE_BACK to close the
-     * dialog.
+     * <p>The default implementation consumed the KEYCODE_BACK to later
+     * handle it in {@link #onKeyUp}.
      *
      * @see #onKeyUp
      * @see android.view.KeyEvent
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK) {
-            if (mCancelable) {
-                cancel();
-            }
+            event.startTracking();
             return true;
         }
 
@@ -499,12 +497,29 @@
     }
 
     /**
+     * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+     * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+     * the event).
+     */
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    /**
      * A key was released.
      * 
+     * <p>The default implementation handles KEYCODE_BACK to close the
+     * dialog.
+     *
      * @see #onKeyDown
      * @see KeyEvent
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+                && !event.isCanceled()) {
+            onBackPressed();
+            return true;
+        }
         return false;
     }
 
@@ -518,6 +533,17 @@
     }
     
     /**
+     * Called when the dialog has detected the user's press of the back
+     * key.  The default implementation simply cancels the dialog (only if
+     * it is cancelable), but you can override this to do whatever you want.
+     */
+    public void onBackPressed() {
+        if (mCancelable) {
+            cancel();
+        }
+    }
+    
+    /**
      * Called when a touch screen event was not handled by any of the views
      * under it. This is most useful to process touch events that happen outside
      * of your window bounds, where there is no view to receive it.
@@ -599,7 +625,8 @@
         if (mWindow.superDispatchKeyEvent(event)) {
             return true;
         }
-        return event.dispatch(this);
+        return event.dispatch(this, mDecor != null
+                ? mDecor.getKeyDispatcherState() : null, this);
     }
 
     /**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 75e4669..75a90c4 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -51,7 +51,6 @@
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.KeyEvent;
-import android.view.Menu;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -745,11 +744,9 @@
             return true;
         }
         
-        if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() < 1) {
-            // If the search key is pressed, toggle between global and in-app search. If we are
-            // currently doing global search and there is no in-app search context to toggle to,
-            // just don't do anything.
-            return toggleGlobalSearch();
+        if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+            // Consume search key for later use.
+            return true;
         }
 
         // if it's an action specified by the searchable activity, launch the
@@ -763,6 +760,29 @@
         return false;
     }
     
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (DBG) Log.d(LOG_TAG, "onKeyUp(" + keyCode + "," + event + ")");
+        if (mSearchable == null) {
+            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
+            // currently doing global search and there is no in-app search context to toggle to,
+            // just don't do anything.
+            return toggleGlobalSearch();
+        }
+        
+        return false;
+    }
+    
     /**
      * Callback to watch the textedit field for empty/non-empty
      */
@@ -1500,21 +1520,24 @@
      * 
      * @return <code>true</code> if there was a previous component that we could go back to.
      */
-    private boolean backToPreviousComponent() {
+    private boolean backToPreviousComponent(boolean doIt) {
         ComponentName previous = popPreviousComponent();
         if (previous == null) {
             return false;
         }
-        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 (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);
+        }
         
         return true;
     }
@@ -1743,24 +1766,41 @@
             if (mSearchDialog.mSearchable == null) {
                 return false;
             }
-            if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
-                if (mSearchDialog.backToPreviousComponent()) {
-                    return true;
+            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)) {
+                        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)) {
+                        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())) {
+                        mSearchDialog.cancel();
+                        return true;
+                    }
+                    return false; // will dismiss soft keyboard if necessary
                 }
-                // 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())) {
-                    mSearchDialog.cancel();
-                    return true;
-                }
-                return false; // will dismiss soft keyboard if necessary
             }
             return false;
         }
@@ -1772,11 +1812,20 @@
     }
     
     protected boolean handleBackKey(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
-            if (backToPreviousComponent()) {
+        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;
             }
-            cancel();
+            if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking()
+                    && !event.isCanceled()) {
+                if (backToPreviousComponent(true)) {
+                    return true;
+                }
+                cancel();
+            }
             return true;
         }
         return false;
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 8730288..8f7e8ca 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -395,7 +395,7 @@
             Drawable.ConstantState cachedBg = mBackgroundsCache.get(backgroundColor);
             if (cachedBg != null) {
                 if (DBG) Log.d(LOG_TAG, "Background cache hit for color " + backgroundColor);
-                return cachedBg.newDrawable();
+                return cachedBg.newDrawable(mProviderContext.getResources());
             }
             if (DBG) Log.d(LOG_TAG, "Creating new background for color " + backgroundColor);
             ColorDrawable transparent = new ColorDrawable(0);
@@ -572,7 +572,7 @@
         Drawable.ConstantState cached = mOutsideDrawablesCache.get(drawableId);
         if (cached != null) {
             if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + drawableId);
-            return cached.newDrawable();
+            return cached.newDrawable(mProviderContext.getResources());
         }
 
         Drawable drawable = null;
@@ -663,7 +663,7 @@
         // Using containsKey() since we also store null values.
         if (mOutsideDrawablesCache.containsKey(componentIconKey)) {
             Drawable.ConstantState cached = mOutsideDrawablesCache.get(componentIconKey);
-            return cached == null ? null : cached.newDrawable();
+            return cached == null ? null : cached.newDrawable(mProviderContext.getResources());
         }
         // Then try the activity or application icon
         Drawable drawable = getActivityIcon(component);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index da40c8a..38cac87 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -22,7 +22,9 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.ColorFilter;
 import android.graphics.Paint;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -56,9 +58,96 @@
     
     private final Context mContext;
     
+    /**
+     * Special drawable that draws a wallpaper as fast as possible.  Assumes
+     * no scaling or placement off (0,0) of the wallpaper (this should be done
+     * at the time the bitmap is loaded).
+     */
+    static class FastBitmapDrawable extends Drawable {
+        private final Bitmap mBitmap;
+        private final int mWidth;
+        private final int mHeight;
+        private int mDrawLeft;
+        private int mDrawTop;
+
+        private FastBitmapDrawable(Bitmap bitmap) {
+            mBitmap = bitmap;
+            mWidth = bitmap.getWidth();
+            mHeight = bitmap.getHeight();
+            setBounds(0, 0, mWidth, mHeight);
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.OPAQUE;
+        }
+
+        @Override
+        public void setBounds(int left, int top, int right, int bottom) {
+            mDrawLeft = left + (right-left - mWidth) / 2;
+            mDrawTop = top + (bottom-top - mHeight) / 2;
+        }
+
+        @Override
+        public void setBounds(Rect bounds) {
+            // TODO Auto-generated method stub
+            super.setBounds(bounds);
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public void setDither(boolean dither) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public void setFilterBitmap(boolean filter) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public int getIntrinsicWidth() {
+            return mWidth;
+        }
+
+        @Override
+        public int getIntrinsicHeight() {
+            return mHeight;
+        }
+
+        @Override
+        public int getMinimumWidth() {
+            return mWidth;
+        }
+
+        @Override
+        public int getMinimumHeight() {
+            return mHeight;
+        }
+    }
+    
     static class Globals extends IWallpaperManagerCallback.Stub {
         private IWallpaperManager mService;
         private Bitmap mWallpaper;
+        private Bitmap mDefaultWallpaper;
         
         private static final int MSG_CLEAR_WALLPAPER = 1;
         
@@ -74,6 +163,7 @@
                         case MSG_CLEAR_WALLPAPER:
                             synchronized (this) {
                                 mWallpaper = null;
+                                mDefaultWallpaper = null;
                             }
                             break;
                     }
@@ -90,12 +180,19 @@
             mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
         }
         
-        public Bitmap peekWallpaperBitmap(Context context) {
+        public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
             synchronized (this) {
                 if (mWallpaper != null) {
                     return mWallpaper;
                 }
+                if (mDefaultWallpaper != null) {
+                    return mDefaultWallpaper;
+                }
                 mWallpaper = getCurrentWallpaperLocked(context);
+                if (mWallpaper == null && returnDefault) {
+                    mDefaultWallpaper = getDefaultWallpaperLocked(context);
+                    return mDefaultWallpaper;
+                }
                 return mWallpaper;
             }
         }
@@ -134,48 +231,48 @@
                         fd.close();
                     } catch (IOException e) {
                     }
-                    if (bm == null) {
+                    
+                    return generateBitmap(context, bm, width, height);
+                }
+            } catch (RemoteException e) {
+            }
+            return null;
+        }
+        
+        private Bitmap getDefaultWallpaperLocked(Context context) {
+            try {
+                InputStream is = context.getResources().openRawResource(
+                        com.android.internal.R.drawable.default_wallpaper);
+                if (is != null) {
+                    int width = mService.getWidthHint();
+                    int height = mService.getHeightHint();
+                    
+                    if (width <= 0 || height <= 0) {
+                        // Degenerate case: no size requested, just load
+                        // bitmap as-is.
+                        Bitmap bm = BitmapFactory.decodeStream(is, null, null);
+                        try {
+                            is.close();
+                        } catch (IOException e) {
+                        }
+                        if (bm != null) {
+                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+                        }
                         return bm;
                     }
-                    bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
                     
-                    // This is the final bitmap we want to return.
-                    Bitmap newbm = Bitmap.createBitmap(width, height,
-                            bm.getConfig());
-                    newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                    Canvas c = new Canvas(newbm);
-                    c.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                    Rect targetRect = new Rect();
-                    targetRect.left = targetRect.top = 0;
-                    targetRect.right = bm.getWidth();
-                    targetRect.bottom = bm.getHeight();
-                    
-                    int deltaw = width - targetRect.right;
-                    int deltah = height - targetRect.bottom;
-                    
-                    if (deltaw > 0 || deltah > 0) {
-                        // We need to scale up so it covers the entire
-                        // area.
-                        float scale = 1.0f;
-                        if (deltaw > deltah) {
-                            scale = width / (float)targetRect.right;
-                        } else {
-                            scale = height / (float)targetRect.bottom;
-                        }
-                        targetRect.right = (int)(targetRect.right*scale);
-                        targetRect.bottom = (int)(targetRect.bottom*scale);
-                        deltaw = width - targetRect.right;
-                        deltah = height - targetRect.bottom;
+                    // Load the bitmap with full color depth, to preserve
+                    // quality for later processing.
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    options.inDither = false;
+                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+                    Bitmap bm = BitmapFactory.decodeStream(is, null, options);
+                    try {
+                        is.close();
+                    } catch (IOException e) {
                     }
                     
-                    targetRect.offset(deltaw/2, deltah/2);
-                    Paint paint = new Paint();
-                    paint.setFilterBitmap(true);
-                    paint.setDither(true);
-                    c.drawBitmap(bm, null, targetRect, paint);
-                    
-                    bm.recycle();
-                    return newbm;
+                    return generateBitmap(context, bm, width, height);
                 }
             } catch (RemoteException e) {
             }
@@ -219,9 +316,13 @@
      * @return Returns a Drawable object that will draw the wallpaper.
      */
     public Drawable getDrawable() {
-        Drawable dr = peekDrawable();
-        return dr != null ? dr : Resources.getSystem().getDrawable(
-                com.android.internal.R.drawable.default_wallpaper);
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
+        if (bm != null) {
+            Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+            dr.setDither(false);
+            return dr;
+        }
+        return null;
     }
 
     /**
@@ -234,8 +335,51 @@
      * null pointer if these is none.
      */
     public Drawable peekDrawable() {
-        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext);
-        return bm != null ? new BitmapDrawable(mContext.getResources(), bm) : null;
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+        if (bm != null) {
+            Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+            dr.setDither(false);
+            return dr;
+        }
+        return null;
+    }
+
+    /**
+     * Like {@link #peekFastDrawable}, but always returns a valid Drawable.  If
+     * no wallpaper is set, the system default wallpaper is returned.
+     *
+     * @return Returns a Drawable object that will draw the wallpaper.
+     */
+    public Drawable getFastDrawable() {
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
+        if (bm != null) {
+            Drawable dr = new FastBitmapDrawable(bm);
+            return dr;
+        }
+        return null;
+    }
+
+    /**
+     * Like {@link #peekDrawable()}, but the returned Drawable has a number
+     * of limitations to reduce its overhead as much as possible: it will
+     * never scale the wallpaper (only centering it if the requested bounds
+     * do match the bitmap bounds, which should not be typical), doesn't
+     * allow setting an alpha, color filter, or other attributes, etc.  The
+     * bounds of the returned drawable will be initialized to the same bounds
+     * as the wallpaper, so normally you will not need to touch it.  The
+     * drawable also assumes that it will be used in a context running in
+     * the same density as the screen (not in density compatibility mode).
+     *
+     * @return Returns an optimized Drawable object that will draw the
+     * wallpaper or a null pointer if these is none.
+     */
+    public Drawable peekFastDrawable() {
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+        if (bm != null) {
+            Drawable dr = new FastBitmapDrawable(bm);
+            return dr;
+        }
+        return null;
     }
 
     /**
@@ -429,8 +573,10 @@
      */
     public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
         try {
+            //Log.v(TAG, "Sending new wallpaper offsets from app...");
             ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, xOffset, yOffset);
+            //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
             // Ignore.
         }
@@ -466,4 +612,51 @@
     public void clear() throws IOException {
         setResource(com.android.internal.R.drawable.default_wallpaper);
     }
+    
+    static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
+        if (bm == null) {
+            return bm;
+        }
+        bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+        
+        // This is the final bitmap we want to return.
+        // XXX We should get the pixel depth from the system (to match the
+        // physical display depth), when there is a way.
+        Bitmap newbm = Bitmap.createBitmap(width, height,
+                Bitmap.Config.RGB_565);
+        newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+        Canvas c = new Canvas(newbm);
+        c.setDensity(DisplayMetrics.DENSITY_DEVICE);
+        Rect targetRect = new Rect();
+        targetRect.left = targetRect.top = 0;
+        targetRect.right = bm.getWidth();
+        targetRect.bottom = bm.getHeight();
+        
+        int deltaw = width - targetRect.right;
+        int deltah = height - targetRect.bottom;
+        
+        if (deltaw > 0 || deltah > 0) {
+            // We need to scale up so it covers the entire
+            // area.
+            float scale = 1.0f;
+            if (deltaw > deltah) {
+                scale = width / (float)targetRect.right;
+            } else {
+                scale = height / (float)targetRect.bottom;
+            }
+            targetRect.right = (int)(targetRect.right*scale);
+            targetRect.bottom = (int)(targetRect.bottom*scale);
+            deltaw = width - targetRect.right;
+            deltah = height - targetRect.bottom;
+        }
+        
+        targetRect.offset(deltaw/2, deltah/2);
+        Paint paint = new Paint();
+        paint.setFilterBitmap(true);
+        paint.setDither(true);
+        c.drawBitmap(bm, null, targetRect, paint);
+        
+        bm.recycle();
+        return newbm;
+    }
 }
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 6d27bc7..1e590f0 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -87,13 +87,37 @@
     private static final long MILLIS_IN_4WEEKS = MILLIS_IN_WEEK * 4;
 
     /** Delay a sync due to local changes this long. In milliseconds */
-    private static final long LOCAL_SYNC_DELAY = 30 * 1000; // 30 seconds
+    private static final long LOCAL_SYNC_DELAY;
 
     /**
      * If a sync takes longer than this and the sync queue is not empty then we will
      * cancel it and add it back to the end of the sync queue. In milliseconds.
      */
-    private static final long MAX_TIME_PER_SYNC = 5 * 60 * 1000; // 5 minutes
+    private static final long MAX_TIME_PER_SYNC;
+
+    static {
+        String localSyncDelayString = SystemProperties.get("sync.local_sync_delay");
+        long localSyncDelay = 30 * 1000; // 30 seconds
+        if (localSyncDelayString != null) {
+            try {
+                localSyncDelay = Long.parseLong(localSyncDelayString);
+            } catch (NumberFormatException nfe) {
+                // ignore, use default
+            }
+        }
+        LOCAL_SYNC_DELAY = localSyncDelay;
+
+        String maxTimePerSyncString = SystemProperties.get("sync.max_time_per_sync");
+        long maxTimePerSync = 5 * 60 * 1000; // 5 minutes
+        if (maxTimePerSyncString != null) {
+            try {
+                maxTimePerSync = Long.parseLong(maxTimePerSyncString);
+            } catch (NumberFormatException nfe) {
+                // ignore, use default
+            }
+        }
+        MAX_TIME_PER_SYNC = maxTimePerSync;
+    }
 
     private static final long SYNC_NOTIFICATION_DELAY = 30 * 1000; // 30 seconds
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ba5c9ed..3796201 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -22,8 +22,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.content.pm.ApplicationInfo;
-import android.graphics.BitmapFactory;
 import android.graphics.Movie;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ColorDrawable;
@@ -1664,7 +1662,7 @@
 
         Drawable.ConstantState cs = sPreloadedDrawables.get(key);
         if (cs != null) {
-            dr = cs.newDrawable();
+            dr = cs.newDrawable(this);
         } else {
             if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
                     value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
@@ -1699,7 +1697,7 @@
                 } else {
                     try {
                         InputStream is = mAssets.openNonAsset(
-                                value.assetCookie, file, AssetManager.ACCESS_BUFFER);
+                                value.assetCookie, file, AssetManager.ACCESS_STREAMING);
         //                System.out.println("Opened file " + file + ": " + is);
                         dr = Drawable.createFromResourceStream(this, value, is,
                                 file, null);
@@ -1745,7 +1743,7 @@
                     //Log.i(TAG, "Returning cached drawable @ #" +
                     //        Integer.toHexString(((Integer)key).intValue())
                     //        + " in " + this + ": " + entry);
-                    return entry.newDrawable();
+                    return entry.newDrawable(this);
                 }
                 else {  // our entry has been purged
                     mDrawableCache.delete(key);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 04daa1c..9991600 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -383,6 +383,20 @@
     private native final void native_autoFocus();
 
     /**
+     * Cancels auto-focus function. If the auto-focus is still in progress,
+     * this function will cancel it. Whether the auto-focus is in progress
+     * or not, this function will return the focus position to the default.
+     * If the camera does not support auto-focus, this is a no-op.
+     * @hide
+     */
+    public final void cancelAutoFocus()
+    {
+        mAutoFocusCallback = null;
+        native_cancelAutoFocus();
+    }
+    private native final void native_cancelAutoFocus();
+
+    /**
      * An interface which contains a callback for the shutter closing after taking a picture.
      */
     public interface ShutterCallback
@@ -1338,5 +1352,3 @@
         }
     };
 }
-
-
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index eedcc35..3619653 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -45,6 +45,9 @@
         implements KeyEvent.Callback {
     private InputMethod mInputMethod;
     
+    final KeyEvent.DispatcherState mDispatcherState
+            = new KeyEvent.DispatcherState();
+
     /**
      * Base class for derived classes to implement their {@link InputMethod}
      * interface.  This takes care of basic maintenance of the input method,
@@ -129,7 +132,8 @@
          * callbacks on the service, and tell the client when this is done.
          */
         public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
-            boolean handled = event.dispatch(AbstractInputMethodService.this);
+            boolean handled = event.dispatch(AbstractInputMethodService.this,
+                    mDispatcherState, this);
             if (callback != null) {
                 callback.finishedEvent(seq, handled);
             }
@@ -148,6 +152,16 @@
     }
     
     /**
+     * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
+     * for used for processing events from the target application.
+     * Normally you will not need to use this directly, but
+     * just use the standard high-level event callbacks like {@link #onKeyDown}.
+     */
+    public KeyEvent.DispatcherState getKeyDispatcherState() {
+        return mDispatcherState;
+    }
+    
+    /**
      * Called by the framework during initialization, when the InputMethod
      * interface for this service needs to be created.
      */
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 1f640ea..5499bba 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -554,7 +554,7 @@
         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        mWindow = new SoftInputWindow(this, mTheme);
+        mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
         initViews();
         mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
     }
@@ -1557,6 +1557,28 @@
         mImm.showSoftInputFromInputMethod(mToken, flags);
     }
     
+    private boolean handleBack(boolean doIt) {
+        if (mShowInputRequested) {
+            // If the soft input area is shown, back closes it and we
+            // consume the back key.
+            if (doIt) requestHideSelf(0);
+            return true;
+        } else if (mWindowVisible) {
+            if (mCandidatesVisibility == View.VISIBLE) {
+                // If we are showing candidates even if no input area, then
+                // hide them.
+                if (doIt) setCandidatesViewShown(false);
+            } else {
+                // If we have the window visible for some other reason --
+                // most likely to show candidates -- then just get rid
+                // of it.  This really shouldn't happen, but just in case...
+                if (doIt) hideWindow();
+            }
+            return true;
+        }
+        return false;
+    }
+    
     /**
      * Override this to intercept key down events before they are processed by the
      * application.  If you return true, the application will not itself
@@ -1564,38 +1586,33 @@
      * will occur as if the IME had not seen the event at all.
      * 
      * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
-     * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown.  In
-     * additional, in fullscreen mode only, it will consume DPAD movement
+     * KeyEvent.KEYCODE_BACK} if the IME is currently shown, to
+     * possibly hide it when the key goes up (if not canceled or long pressed).  In
+     * addition, in fullscreen mode only, it will consume DPAD movement
      * events to move the cursor in the extracted text view, not allowing
      * them to perform navigation in the underlying application.
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
-                && event.getRepeatCount() == 0) {
-            if (mShowInputRequested) {
-                // If the soft input area is shown, back closes it and we
-                // consume the back key.
-                requestHideSelf(0);
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            if (handleBack(false)) {
+                event.startTracking();
                 return true;
-            } else if (mWindowVisible) {
-                if (mCandidatesVisibility == View.VISIBLE) {
-                    // If we are showing candidates even if no input area, then
-                    // hide them.
-                    setCandidatesViewShown(false);
-                    return true;
-                } else {
-                    // If we have the window visible for some other reason --
-                    // most likely to show candidates -- then just get rid
-                    // of it.  This really shouldn't happen, but just in case...
-                    hideWindow();
-                    return true;
-                }
             }
+            return false;
         }
         return doMovementKey(keyCode, event, MOVEMENT_DOWN);
     }
 
     /**
+     * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+     * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+     * the event).
+     */
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    /**
      * Override this to intercept special key multiple events before they are
      * processed by the
      * application.  If you return true, the application will not itself
@@ -1617,12 +1634,18 @@
      * process the event.  If you return true, the normal application processing
      * will occur as if the IME had not seen the event at all.
      * 
-     * <p>The default implementation always returns false, except when
-     * in fullscreen mode, where it will consume DPAD movement
+     * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
+     * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown.  In
+     * addition, in fullscreen mode only, it will consume DPAD movement
      * events to move the cursor in the extracted text view, not allowing
      * them to perform navigation in the underlying application.
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isTracking()
+                && !event.isCanceled()) {
+            return handleBack(true);
+        }
+        
         return doMovementKey(keyCode, event, MOVEMENT_UP);
     }
 
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index d91ace6..6a54846 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -21,6 +21,7 @@
 import android.content.pm.ActivityInfo;
 import android.os.IBinder;
 import android.view.Gravity;
+import android.view.KeyEvent;
 import android.view.WindowManager;
 
 /**
@@ -30,7 +31,8 @@
  * always visible.
  */
 class SoftInputWindow extends Dialog {
-
+    final KeyEvent.DispatcherState mDispatcherState;
+    
     public void setToken(IBinder token) {
         WindowManager.LayoutParams lp = getWindow().getAttributes();
         lp.token = token;
@@ -49,11 +51,19 @@
      *        using styles. This theme is applied on top of the current theme in
      *        <var>context</var>. If 0, the default dialog theme will be used.
      */
-    public SoftInputWindow(Context context, int theme) {
+    public SoftInputWindow(Context context, int theme,
+            KeyEvent.DispatcherState dispatcherState) {
         super(context, theme);
+        mDispatcherState = dispatcherState;
         initDockWindow();
     }
 
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        mDispatcherState.reset();
+    }
+
     /**
      * Get the size of the DockWindow.
      * 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6c2a27a..b4778fe 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -143,6 +143,9 @@
          * Service.onStartCommand} function will return the new
          * {@link android.app.Service#START_STICKY} behavior instead of the
          * old compatibility {@link android.app.Service#START_STICKY_COMPATIBILITY}.
+         * <li> The {@link android.app.Activity} class will now execute back
+         * key presses on the key up instead of key down, to be able to detect
+         * canceled presses from virtual keys.
          * </ul>
          */
         public static final int ECLAIR = CUR_DEVELOPMENT;
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 0ce86db..65301e4 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -64,7 +64,7 @@
     /**
      * This method returns the Looper associated with this thread. If this thread not been started
      * or for any reason is isAlive() returns false, this method will return null. If this thread 
-     * has been started, this method will blocked until the looper has been initialized.  
+     * has been started, this method will block until the looper has been initialized.  
      * @return The looper.
      */
     public Looper getLooper() {
@@ -85,6 +85,21 @@
     }
     
     /**
+     * Ask the currently running looper to quit.  If the thread has not
+     * been started or has finished (that is if {@link #getLooper} returns
+     * null), then false is returned.  Otherwise the looper is asked to
+     * quit and true is returned.
+     */
+    public boolean quit() {
+        Looper looper = getLooper();
+        if (looper != null) {
+            looper.quit();
+            return true;
+        }
+        return false;
+    }
+    
+    /**
      * Returns the identifier of this thread. See Process.myTid().
      */
     public int getThreadId() {
diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl
index aebcb3c..a6ef647 100755
--- a/core/java/android/os/IHardwareService.aidl
+++ b/core/java/android/os/IHardwareService.aidl
@@ -32,6 +32,9 @@
     // sets the brightness of the backlights (screen, keyboard, button) 0-255
     void setBacklights(int brightness);
 
+    // enables or disables automatic brightness mode
+    void setAutoBrightness(boolean on);
+
     // for the phone
     void setAttentionLight(boolean on);
 }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d354ccf..b0ac7f4 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -46,6 +46,15 @@
     /** A content:// style uri to the authority for the contacts provider */
     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
+    /**
+     * An optional insert, update or delete URI parameter that allows the caller
+     * to specify that it is a sync adapter. The default value is false. If true
+     * the dirty flag is not automatically set and the "syncToNetwork" parameter
+     * is set to false when calling
+     * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
+     */
+    public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
+
     public interface SyncStateColumns extends SyncStateContract.Columns {
     }
 
@@ -480,7 +489,8 @@
          * called on a raw contact, it is marked for deletion and removed from its
          * aggregate contact. The sync adaptor deletes the raw contact on the server and
          * then calls ContactResolver.delete once more, this time passing the
-         * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
+         * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
+         * the data removal.
          * <P>Type: INTEGER</P>
          */
         public static final String DELETED = "deleted";
@@ -517,14 +527,6 @@
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
 
         /**
-         * Query parameter that can be passed with the {@link #CONTENT_URI} URI
-         * to the {@link android.content.ContentResolver#delete} method to
-         * indicate that the raw contact can be deleted physically, rather than
-         * merely marked as deleted.
-         */
-        public static final String DELETE_PERMANENTLY = "delete_permanently";
-
-        /**
          * Aggregation mode: aggregate asynchronously.
          */
         public static final int AGGREGATION_MODE_DEFAULT = 0;
@@ -648,13 +650,6 @@
         public static final String SYNC3 = "data_sync3";
         /** Generic column for use by sync adapters. */
         public static final String SYNC4 = "data_sync4";
-
-        /**
-         * An optional insert, update or delete URI parameter that determines if
-         * the corresponding raw contact should be marked as dirty. The default
-         * value is true.
-         */
-        public static final String MARK_AS_DIRTY = "mark_as_dirty";
     }
 
     /**
@@ -1533,8 +1528,9 @@
          * for deletion. When {@link android.content.ContentResolver#delete} is
          * called on a raw contact, it is marked for deletion and removed from its
          * aggregate contact. The sync adaptor deletes the raw contact on the server and
-         * then calls ContactResolver.delete once more, this time passing the
-         * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
+         * then calls ContactResolver.delete once more, this time setting the the
+         * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize 
+         * the data removal.
          * <P>Type: INTEGER</P>
          */
         public static final String DELETED = "deleted";
@@ -1579,20 +1575,6 @@
          * The MIME type of a single group.
          */
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
-
-        /**
-         * Query parameter that can be passed with the {@link #CONTENT_URI} URI
-         * to the {@link android.content.ContentResolver#delete} method to
-         * indicate that the raw contact can be deleted physically, rather than
-         * merely marked as deleted.
-         */
-        public static final String DELETE_PERMANENTLY = "delete_permanently";
-
-        /**
-         * An optional update or insert URI parameter that determines if the
-         * group should be marked as dirty. The default value is true.
-         */
-        public static final String MARK_AS_DIRTY = "mark_as_dirty";
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 688f377..0bbd1fc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1061,6 +1061,12 @@
         public static final String SCREEN_BRIGHTNESS = "screen_brightness";
 
         /**
+         * Control whether to enable automatic brightness mode.
+         * @hide
+         */
+        public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
+
+        /**
          * Control whether the process CPU usage meter should be shown.
          */
         public static final String SHOW_PROCESSES = "show_processes";
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 78e2c27..de0cad7 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -398,14 +398,14 @@
         // Parrot, Zhongshan General K-mate Electronics, Great Well
         // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
         // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
-        // Continental Automotive, Harman/Becker
+        // Continental Automotive, Harman/Becker, Panasonic/Kyushu Ten
         private final ArrayList<String>  mAutoPairingAddressBlacklist =
                 new ArrayList<String>(Arrays.asList(
                         "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
                         "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
                         "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
                         "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
-                        "00:0A:30", "00:1E:AE", "00:1C:D7"
+                        "00:0A:30", "00:1E:AE", "00:1C:D7", "00:80:F0"
                         ));
 
         // List of names of Bluetooth devices for which auto pairing should be
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e5659d5..cd5cf10 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -28,9 +28,11 @@
 import android.content.IntentFilter;
 import android.graphics.Rect;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.LogPrinter;
 import android.view.Gravity;
 import android.view.IWindowSession;
 import android.view.MotionEvent;
@@ -74,6 +76,8 @@
     private static final int MSG_WINDOW_RESIZED = 10030;
     private static final int MSG_TOUCH_EVENT = 10040;
     
+    private Looper mCallbackLooper;
+    
     /**
      * The actual implementation of a wallpaper.  A wallpaper service may
      * have multiple instances running (for example as a real wallpaper
@@ -120,6 +124,7 @@
         boolean mOffsetMessageEnqueued;
         float mPendingXOffset;
         float mPendingYOffset;
+        boolean mPendingSync;
         MotionEvent mPendingMove;
         
         final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -212,10 +217,14 @@
             }
 
             @Override
-            public void dispatchWallpaperOffsets(float x, float y) {
+            public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
                 synchronized (mLock) {
+                    if (DEBUG) Log.v(TAG, "Dispatch wallpaper offsets: " + x + ", " + y);
                     mPendingXOffset = x;
                     mPendingYOffset = y;
+                    if (sync) {
+                        mPendingSync = true;
+                    }
                     if (!mOffsetMessageEnqueued) {
                         mOffsetMessageEnqueued = true;
                         Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
@@ -551,9 +560,12 @@
             
             float xOffset;
             float yOffset;
+            boolean sync;
             synchronized (mLock) {
                 xOffset = mPendingXOffset;
                 yOffset = mPendingYOffset;
+                sync = mPendingSync;
+                mPendingSync = false;
                 mOffsetMessageEnqueued = false;
             }
             if (DEBUG) Log.v(TAG, "Offsets change in " + this
@@ -563,6 +575,14 @@
             final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
             final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
             onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+            
+            if (sync) {
+                try {
+                    if (DEBUG) Log.v(TAG, "Reporting offsets change complete");
+                    mSession.wallpaperOffsetsComplete(mWindow.asBinder());
+                } catch (RemoteException e) {
+                }
+            }
         }
         
         void detach() {
@@ -622,7 +642,13 @@
         IWallpaperEngineWrapper(WallpaperService context,
                 IWallpaperConnection conn, IBinder windowToken,
                 int windowType, boolean isPreview, int reqWidth, int reqHeight) {
-            mCaller = new HandlerCaller(context, this);
+            if (DEBUG && mCallbackLooper != null) {
+                mCallbackLooper.setMessageLogging(new LogPrinter(Log.VERBOSE, TAG));
+            }
+            mCaller = new HandlerCaller(context,
+                    mCallbackLooper != null
+                            ? mCallbackLooper : context.getMainLooper(),
+                    this);
             mConnection = conn;
             mWindowToken = windowToken;
             mWindowType = windowType;
@@ -736,5 +762,18 @@
         return new IWallpaperServiceWrapper(this);
     }
     
+    /**
+     * This allows subclasses to change the thread that most callbacks
+     * occur on.  Currently hidden because it is mostly needed for the
+     * image wallpaper (which runs in the system process and doesn't want
+     * to get stuck running on that seriously in use main thread).  Not
+     * exposed right now because the semantics of this are not totally
+     * well defined and some callbacks can still happen on the main thread).
+     * @hide
+     */
+    public void setCallbackLooper(Looper looper) {
+        mCallbackLooper = looper;
+    }
+    
     public abstract Engine onCreateEngine();
 }
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index ebc5f7b..b7953af 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -60,5 +60,5 @@
     /**
      * Called for wallpaper windows when their offsets change.
      */
-    void dispatchWallpaperOffsets(float x, float y);
+    void dispatchWallpaperOffsets(float x, float y, boolean sync);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 4d662d2..9b8b6d4 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -114,4 +114,6 @@
      * larger than the screen, set the offset within the screen.
      */
     void setWallpaperPosition(IBinder windowToken, float x, float y);
+    
+    void wallpaperOffsetsComplete(IBinder window);
 }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index f9b16fc..d4f9787 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -18,6 +18,8 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseIntArray;
 import android.view.KeyCharacterMap;
 import android.view.KeyCharacterMap.KeyData;
 
@@ -277,6 +279,32 @@
     public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
     
     /**
+     * This flag is set for the first key repeat that occurs after the
+     * long press timeout.
+     */
+    public static final int FLAG_LONG_PRESS = 0x80;
+    
+    /**
+     * Set when a key event has {@link #FLAG_CANCELED} set because a long
+     * press action was executed while it was down. 
+     */
+    public static final int FLAG_CANCELED_LONG_PRESS = 0x100;
+    
+    /**
+     * Set for {@link #ACTION_UP} when this event's key code is still being
+     * tracked from its initial down.  That is, somebody requested that tracking
+     * started on the key down and a long press has not caused
+     * the tracking to be canceled.
+     */
+    public static final int FLAG_TRACKING = 0x200;
+    
+    /**
+     * Private control to determine when an app is tracking a key sequence.
+     * @hide
+     */
+    public static final int FLAG_START_TRACKING = 0x40000000;
+    
+    /**
      * Returns the maximum keycode.
      */
     public static int getMaxKeyCode() {
@@ -292,6 +320,9 @@
         return KeyCharacterMap.getDeadChar(accent, c);
     }
     
+    static final boolean DEBUG = false;
+    static final String TAG = "KeyEvent";
+    
     private int mMetaState;
     private int mAction;
     private int mKeyCode;
@@ -305,7 +336,11 @@
 
     public interface Callback {
         /**
-         * Called when a key down event has occurred.
+         * Called when a key down event has occurred.  If you return true,
+         * you can first call {@link KeyEvent#startTracking()
+         * KeyEvent.startTracking()} to have the framework track the event
+         * through its {@link #onKeyUp(int, KeyEvent)} and also call your
+         * {@link #onKeyLongPress(int, KeyEvent)} if it occurs.
          * 
          * @param keyCode The value in event.getKeyCode().
          * @param event Description of the key event.
@@ -316,6 +351,22 @@
         boolean onKeyDown(int keyCode, KeyEvent event);
 
         /**
+         * Called when a long press has occurred.  If you return true,
+         * the final key up will have {@link KeyEvent#FLAG_CANCELED} and
+         * {@link KeyEvent#FLAG_CANCELED_LONG_PRESS} set.  Note that in
+         * order to receive this callback, someone in the event change
+         * <em>must</em> return true from {@link #onKeyDown} <em>and</em>
+         * call {@link KeyEvent#startTracking()} on the event.
+         * 
+         * @param keyCode The value in event.getKeyCode().
+         * @param event Description of the key event.
+         * 
+         * @return If you handled the event, return true.  If you want to allow
+         *         the event to be handled by the next receiver, return false.
+         */
+        boolean onKeyLongPress(int keyCode, KeyEvent event);
+
+        /**
          * Called when a key up event has occurred.
          * 
          * @param keyCode The value in event.getKeyCode().
@@ -500,11 +551,15 @@
     /**
      * Copy an existing key event, modifying its time and repeat count.
      * 
+     * @deprecated Use {@link #changeTimeRepeat(KeyEvent, long, int)}
+     * instead.
+     * 
      * @param origEvent The existing event to be copied.
      * @param eventTime The new event time
      * (in {@link android.os.SystemClock#uptimeMillis}) of the event.
      * @param newRepeat The new repeat count of the event.
      */
+    @Deprecated
     public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
         mDownTime = origEvent.mDownTime;
         mEventTime = eventTime;
@@ -533,6 +588,26 @@
     }
     
     /**
+     * Create a new key event that is the same as the given one, but whose
+     * event time and repeat count are replaced with the given value.
+     * 
+     * @param event The existing event to be copied.  This is not modified.
+     * @param eventTime The new event time
+     * (in {@link android.os.SystemClock#uptimeMillis}) of the event.
+     * @param newRepeat The new repeat count of the event.
+     * @param newFlags New flags for the event, replacing the entire value
+     * in the original event.
+     */
+    public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime,
+            int newRepeat, int newFlags) {
+        KeyEvent ret = new KeyEvent(event);
+        ret.mEventTime = eventTime;
+        ret.mRepeatCount = newRepeat;
+        ret.mFlags = newFlags;
+        return ret;
+    }
+    
+    /**
      * Copy an existing key event, modifying its action.
      * 
      * @param origEvent The existing event to be copied.
@@ -721,6 +796,34 @@
     }
     
     /**
+     * Call this during {@link Callback#onKeyDown} to have the system track
+     * the key through its final up (possibly including a long press).  Note
+     * that only one key can be tracked at a time -- if another key down
+     * event is received while a previous one is being tracked, tracking is
+     * stopped on the previous event.
+     */
+    public final void startTracking() {
+        mFlags |= FLAG_START_TRACKING;
+    }
+    
+    /**
+     * For {@link #ACTION_UP} events, indicates that the event is still being
+     * tracked from its initial down event as per
+     * {@link #FLAG_TRACKING}.
+     */
+    public final boolean isTracking() {
+        return (mFlags&FLAG_TRACKING) != 0;
+    }
+    
+    /**
+     * For {@link #ACTION_DOWN} events, indicates that the event has been
+     * canceled as per {@link #FLAG_LONG_PRESS}.
+     */
+    public final boolean isLongPress() {
+        return (mFlags&FLAG_LONG_PRESS) != 0;
+    }
+    
+    /**
      * Retrieve the key code of the key event.  This is the physical key that
      * was pressed, <em>not</em> the Unicode character.
      * 
@@ -906,19 +1009,55 @@
     }
     
     /**
+     * @deprecated Use {@link #dispatch(Callback, DispatcherState, Object)} instead.
+     */
+    @Deprecated
+    public final boolean dispatch(Callback receiver) {
+        return dispatch(receiver, null, null);
+    }
+    
+    /**
      * Deliver this key event to a {@link Callback} interface.  If this is
      * an ACTION_MULTIPLE event and it is not handled, then an attempt will
      * be made to deliver a single normal event.
      * 
      * @param receiver The Callback that will be given the event.
+     * @param state State information retained across events.
+     * @param target The target of the dispatch, for use in tracking.
      * 
      * @return The return value from the Callback method that was called.
      */
-    public final boolean dispatch(Callback receiver) {
+    public final boolean dispatch(Callback receiver, DispatcherState state,
+            Object target) {
         switch (mAction) {
-            case ACTION_DOWN:
-                return receiver.onKeyDown(mKeyCode, this);
+            case ACTION_DOWN: {
+                mFlags &= ~FLAG_START_TRACKING;
+                if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state
+                        + ": " + this);
+                boolean res = receiver.onKeyDown(mKeyCode, this);
+                if (state != null) {
+                    if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
+                        if (DEBUG) Log.v(TAG, "  Start tracking!");
+                        state.startTracking(this, target);
+                    } else if (isLongPress() && state.isTracking(this)) {
+                        try {
+                            if (receiver.onKeyLongPress(mKeyCode, this)) {
+                                if (DEBUG) Log.v(TAG, "  Clear from long press!");
+                                state.performedLongPress(this);
+                                res = true;
+                            }
+                        } catch (AbstractMethodError e) {
+                        }
+                    }
+                }
+                return res;
+            }
             case ACTION_UP:
+                if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state
+                        + ": " + this);
+                if (state != null) {
+                    state.handleUpEvent(this);
+                }
                 return receiver.onKeyUp(mKeyCode, this);
             case ACTION_MULTIPLE:
                 final int count = mRepeatCount;
@@ -938,10 +1077,103 @@
                     mRepeatCount = count;
                     return handled;
                 }
+                return false;
         }
         return false;
     }
 
+    /**
+     * Use with {@link KeyEvent#dispatch(Callback, DispatcherState, Object)}
+     * for more advanced key dispatching, such as long presses.
+     */
+    public static class DispatcherState {
+        int mDownKeyCode;
+        Object mDownTarget;
+        SparseIntArray mActiveLongPresses = new SparseIntArray();
+        
+        /**
+         * Reset back to initial state.
+         */
+        public void reset() {
+            if (DEBUG) Log.v(TAG, "Reset: " + this);
+            mDownKeyCode = 0;
+            mDownTarget = null;
+            mActiveLongPresses.clear();
+        }
+        
+        /**
+         * Stop any tracking associated with this target.
+         */
+        public void reset(Object target) {
+            if (mDownTarget == target) {
+                if (DEBUG) Log.v(TAG, "Reset in " + target + ": " + this);
+                mDownKeyCode = 0;
+                mDownTarget = null;
+            }
+        }
+        
+        /**
+         * Start tracking the key code associated with the given event.  This
+         * can only be called on a key down.  It will allow you to see any
+         * long press associated with the key, and will result in
+         * {@link KeyEvent#isTracking} return true on the long press and up
+         * events.
+         * 
+         * <p>This is only needed if you are directly dispatching events, rather
+         * than handling them in {@link Callback#onKeyDown}.
+         */
+        public void startTracking(KeyEvent event, Object target) {
+            if (event.getAction() != ACTION_DOWN) {
+                throw new IllegalArgumentException(
+                        "Can only start tracking on a down event");
+            }
+            if (DEBUG) Log.v(TAG, "Start trackingt in " + target + ": " + this);
+            mDownKeyCode = event.getKeyCode();
+            mDownTarget = target;
+        }
+        
+        /**
+         * Return true if the key event is for a key code that is currently
+         * being tracked by the dispatcher.
+         */
+        public boolean isTracking(KeyEvent event) {
+            return mDownKeyCode == event.getKeyCode();
+        }
+        
+        /**
+         * Keep track of the given event's key code as having performed an
+         * action with a long press, so no action should occur on the up.
+         * <p>This is only needed if you are directly dispatching events, rather
+         * than handling them in {@link Callback#onKeyLongPress}.
+         */
+        public void performedLongPress(KeyEvent event) {
+            mActiveLongPresses.put(event.getKeyCode(), 1);
+        }
+        
+        /**
+         * Handle key up event to stop tracking.  This resets the dispatcher state,
+         * and updates the key event state based on it.
+         * <p>This is only needed if you are directly dispatching events, rather
+         * than handling them in {@link Callback#onKeyUp}.
+         */
+        public void handleUpEvent(KeyEvent event) {
+            final int keyCode = event.getKeyCode();
+            if (DEBUG) Log.v(TAG, "Handle key up " + event + ": " + this);
+            int index = mActiveLongPresses.indexOfKey(keyCode);
+            if (index >= 0) {
+                if (DEBUG) Log.v(TAG, "  Index: " + index);
+                event.mFlags |= FLAG_CANCELED | FLAG_CANCELED_LONG_PRESS;
+                mActiveLongPresses.removeAt(index);
+            }
+            if (mDownKeyCode == keyCode) {
+                if (DEBUG) Log.v(TAG, "  Tracking!");
+                event.mFlags |= FLAG_TRACKING;
+                mDownKeyCode = 0;
+                mDownTarget = null;
+            }
+        }
+    }
+    
     public String toString() {
         return "KeyEvent{action=" + mAction + " code=" + mKeyCode
             + " repeat=" + mRepeatCount
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1426aef..356f55a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -236,6 +236,10 @@
 
     @Override
     public boolean gatherTransparentRegion(Region region) {
+        if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+            return super.gatherTransparentRegion(region);
+        }
+        
         boolean opaque = true;
         if ((mPrivateFlags & SKIP_DRAW) == 0) {
             // this view draws, remove it from the transparent region
@@ -259,20 +263,24 @@
 
     @Override
     public void draw(Canvas canvas) {
-        // draw() is not called when SKIP_DRAW is set
-        if ((mPrivateFlags & SKIP_DRAW) == 0) {
-            // punch a whole in the view-hierarchy below us
-            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+        if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+            // draw() is not called when SKIP_DRAW is set
+            if ((mPrivateFlags & SKIP_DRAW) == 0) {
+                // punch a whole in the view-hierarchy below us
+                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+            }
         }
         super.draw(canvas);
     }
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        // if SKIP_DRAW is cleared, draw() has already punched a hole
-        if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
-            // punch a whole in the view-hierarchy below us
-            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+        if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+            // if SKIP_DRAW is cleared, draw() has already punched a hole
+            if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+                // punch a whole in the view-hierarchy below us
+                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+            }
         }
         // reposition ourselves where the surface is 
         mHaveFrame = true;
@@ -281,6 +289,22 @@
     }
 
     /**
+     * Control whether the surface view's surface is placed on top of its
+     * window.  Normally it is placed behind the window, to allow it to
+     * (for the most part) appear to composite with the views in the
+     * hierarchy.  By setting this, you cause it to be placed above the
+     * window.  This means that none of the contents of the window this
+     * SurfaceView is in will be visible on top of its surface.
+     * 
+     * <p>Note that this must be set before the surface view's containing
+     * window is attached to the window manager.
+     */
+    public void setOnTop(boolean onTop) {
+        mWindowType = onTop ? WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
+                : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+    }
+    
+    /**
      * Hack to allow special layering of windows.  The type is one of the
      * types in WindowManager.LayoutParams.  This is a hack so:
      * @hide
@@ -345,7 +369,9 @@
                 }
                 
                 mLayout.format = mRequestedFormat;
-                mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                              | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                              | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                               | WindowManager.LayoutParams.FLAG_SCALED
                               | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                               | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f63c2f1..6ff0fc8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2600,6 +2600,10 @@
         if (mOnFocusChangeListener != null) {
             mOnFocusChangeListener.onFocusChange(this, gainFocus);
         }
+        
+        if (mAttachInfo != null) {
+            mAttachInfo.mKeyDispatchState.reset(this);
+        }
     }
 
     /**
@@ -3609,6 +3613,16 @@
     }
 
     /**
+     * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
+     * for this view's window.  Returns null if the view is not currently attached
+     * to the window.  Normally you will not need to use this directly, but
+     * just use the standard high-level event callbacks like {@link #onKeyDown}.
+     */
+    public KeyEvent.DispatcherState getKeyDispatcherState() {
+        return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null;
+    }
+    
+    /**
      * Dispatch a key event before it is processed by any input method
      * associated with the view hierarchy.  This can be used to intercept
      * key events in special situations before the IME consumes them; a
@@ -3645,7 +3659,8 @@
             return true;
         }
 
-        return event.dispatch(this);
+        return event.dispatch(this, mAttachInfo != null
+                ? mAttachInfo.mKeyDispatchState : null, this);
     }
 
     /**
@@ -3910,6 +3925,15 @@
     }
 
     /**
+     * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+     * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+     * the event).
+     */
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    /**
      * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
      * KeyEvent.Callback.onKeyMultiple()}: perform clicking of the view
      * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
@@ -6042,12 +6066,11 @@
         int height = mBottom - mTop;
 
         final AttachInfo attachInfo = mAttachInfo;
-        final float scale = attachInfo.mApplicationScale;
+        final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
         width = (int) ((width * scale) + 0.5f);
         height = (int) ((height * scale) + 0.5f);
         
-        Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1,
-                height > 0 ? height : 1, quality);
+        Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
         if (bitmap == null) {
             throw new OutOfMemoryError();
         }
@@ -8573,6 +8596,9 @@
          */
         final ArrayList<View> mScrollContainers = new ArrayList<View>();
 
+        final KeyEvent.DispatcherState mKeyDispatchState
+                = new KeyEvent.DispatcherState();
+
         /**
          * Indicates whether the view's window currently has the focus.
          */
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index b61465a..c6937a3 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1812,6 +1812,7 @@
                     if (hasWindowFocus && imm != null && mLastWasImTarget) {
                         imm.startGettingWindowFocus(mView);
                     }
+                    mAttachInfo.mKeyDispatchState.reset();
                     mView.dispatchWindowFocusChanged(hasWindowFocus);
                 }
 
@@ -2868,7 +2869,13 @@
             }
         }
         
-        public void dispatchWallpaperOffsets(float x, float y) {
+        public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
+            if (sync) {
+                try {
+                    sWindowSession.wallpaperOffsetsComplete(asBinder());
+                } catch (RemoteException e) {
+                }
+            }
         }
     }
 
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index db6b74f..465eef8 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -222,7 +222,6 @@
 
     private void resetLoadingStates() {
         mCommitted = true;
-        mWebViewCore.mEndScaleZoom = mFirstLayoutDone == false;
         mFirstLayoutDone = true;
     }
 
@@ -245,7 +244,6 @@
             // blocking the update in {@link #loadStarted}
             mWebViewCore.contentDraw();
         }
-        mWebViewCore.mEndScaleZoom = true;
     }
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 0f178e9..10939fd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -25,8 +25,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
 import android.graphics.Picture;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -59,7 +57,6 @@
 import android.view.ViewParent;
 import android.view.ViewTreeObserver;
 import android.view.animation.AlphaAnimation;
-import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebTextView.AutoCompleteAdapter;
 import android.webkit.WebViewCore.EventHub;
@@ -68,9 +65,7 @@
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.ListView;
-import android.widget.ScrollBarDrawable;
 import android.widget.Scroller;
 import android.widget.Toast;
 import android.widget.ZoomButtonsController;
@@ -219,13 +214,13 @@
             inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true);
             mPlusMinusZoomControls = (ZoomControls) findViewById(
                     com.android.internal.R.id.zoomControls);
-            mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify);
+            findViewById(com.android.internal.R.id.zoomMagnify).setVisibility(
+                    View.GONE);
         }
 
         public void show(boolean showZoom, boolean canZoomOut) {
             mPlusMinusZoomControls.setVisibility(
                     showZoom ? View.VISIBLE : View.GONE);
-            mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE);
             fade(View.VISIBLE, 0.0f, 1.0f);
         }
 
@@ -240,12 +235,8 @@
             setVisibility(visibility);
         }
 
-        public void setIsZoomMagnifyEnabled(boolean isEnabled) {
-            mZoomMagnify.setEnabled(isEnabled);
-        }
-
         public boolean hasFocus() {
-            return mPlusMinusZoomControls.hasFocus() || mZoomMagnify.hasFocus();
+            return mPlusMinusZoomControls.hasFocus();
         }
 
         public void setOnZoomInClickListener(OnClickListener listener) {
@@ -256,12 +247,7 @@
             mPlusMinusZoomControls.setOnZoomOutClickListener(listener);
         }
 
-        public void setOnZoomMagnifyClickListener(OnClickListener listener) {
-            mZoomMagnify.setOnClickListener(listener);
-        }
-
         ZoomControls    mPlusMinusZoomControls;
-        ImageView       mZoomMagnify;
     }
 
     /**
@@ -351,9 +337,6 @@
     private float mLastVelX;
     private float mLastVelY;
 
-    // use this flag to control whether enabling the new double tap zoom
-    static final boolean ENABLE_DOUBLETAP_ZOOM = true;
-
     /**
      * Touch mode
      */
@@ -363,17 +346,9 @@
     private static final int TOUCH_DRAG_MODE = 3;
     private static final int TOUCH_SHORTPRESS_START_MODE = 4;
     private static final int TOUCH_SHORTPRESS_MODE = 5;
-    private static final int TOUCH_DOUBLECLICK_MODE = 6;
+    private static final int TOUCH_DOUBLE_TAP_MODE = 6;
     private static final int TOUCH_DONE_MODE = 7;
     private static final int TOUCH_SELECT_MODE = 8;
-    // touch mode values specific to scale+scroll
-    private static final int FIRST_SCROLL_ZOOM = 9;
-    private static final int SCROLL_ZOOM_ANIMATION_IN = 9;
-    private static final int SCROLL_ZOOM_ANIMATION_OUT = 10;
-    private static final int SCROLL_ZOOM_OUT = 11;
-    private static final int LAST_SCROLL_ZOOM = 11;
-    // end of touch mode values specific to scale+scroll
-    private static final int TOUCH_DOUBLE_TAP_MODE = 12;
 
     // Whether to forward the touch events to WebCore
     private boolean mForwardTouchEvents = false;
@@ -1394,6 +1369,7 @@
      * Reload the current url.
      */
     public void reload() {
+        clearTextEntry();
         switchOutDrawHistory();
         mWebViewCore.sendMessage(EventHub.RELOAD);
     }
@@ -1834,23 +1810,50 @@
         return contentToViewDimension(y) + getTitleHeight();
     }
 
+    private Rect contentToViewRect(Rect x) {
+        return new Rect(contentToViewX(x.left), contentToViewY(x.top),
+                        contentToViewX(x.right), contentToViewY(x.bottom));
+    }
+
+    /*  To invalidate a rectangle in content coordinates, we need to transform
+        the rect into view coordinates, so we can then call invalidate(...).
+
+        Normally, we would just call contentToView[XY](...), which eventually
+        calls Math.round(coordinate * mActualScale). However, for invalidates,
+        we need to account for the slop that occurs with antialiasing. To
+        address that, we are a little more liberal in the size of the rect that
+        we invalidate.
+
+        This liberal calculation calls floor() for the top/left, and ceil() for
+        the bottom/right coordinates. This catches the possible extra pixels of
+        antialiasing that we might have missed with just round().
+     */
+
     // Called by JNI to invalidate the View, given rectangle coordinates in
     // content space
     private void viewInvalidate(int l, int t, int r, int b) {
-        invalidate(contentToViewX(l), contentToViewY(t), contentToViewX(r),
-                contentToViewY(b));
+        final float scale = mActualScale;
+        final int dy = getTitleHeight();
+        invalidate((int)Math.floor(l * scale),
+                   (int)Math.floor(t * scale) + dy,
+                   (int)Math.ceil(r * scale),
+                   (int)Math.ceil(b * scale) + dy);
     }
 
     // Called by JNI to invalidate the View after a delay, given rectangle
     // coordinates in content space
     private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
-        postInvalidateDelayed(delay, contentToViewX(l), contentToViewY(t),
-                contentToViewX(r), contentToViewY(b));
+        final float scale = mActualScale;
+        final int dy = getTitleHeight();
+        postInvalidateDelayed(delay,
+                              (int)Math.floor(l * scale),
+                              (int)Math.floor(t * scale) + dy,
+                              (int)Math.ceil(r * scale),
+                              (int)Math.ceil(b * scale) + dy);
     }
 
-    private Rect contentToView(Rect x) {
-        return new Rect(contentToViewX(x.left), contentToViewY(x.top)
-                , contentToViewX(x.right), contentToViewY(x.bottom));
+    private void invalidateContentRect(Rect r) {
+        viewInvalidate(r.left, r.top, r.right, r.bottom);
     }
 
     // stop the scroll animation, and don't let a subsequent fling add
@@ -2674,32 +2677,19 @@
         if (mNativeClass == 0) {
             return;
         }
-        if (mWebViewCore.mEndScaleZoom) {
-            mWebViewCore.mEndScaleZoom = false;
-            if (mTouchMode >= FIRST_SCROLL_ZOOM
-                    && mTouchMode <= LAST_SCROLL_ZOOM) {
-                setHorizontalScrollBarEnabled(true);
-                setVerticalScrollBarEnabled(true);
-                mTouchMode = TOUCH_DONE_MODE;
-            }
-        }
         canvas.save();
-        if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
-            scrollZoomDraw(canvas);
-        } else {
-            // Update the buttons in the picture, so when we draw the picture
-            // to the screen, they are in the correct state.
-            // Tell the native side if user is a) touching the screen,
-            // b) pressing the trackball down, or c) pressing the enter key
-            // If the cursor is on a button, we need to draw it in the pressed
-            // state.
-            // If mNativeClass is 0, we should not reach here, so we do not
-            // need to check it again.
-            nativeRecordButtons(hasFocus() && hasWindowFocus(),
-                    mTouchMode == TOUCH_SHORTPRESS_START_MODE
-                    || mTrackballDown || mGotCenterDown, false);
-            drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
-        }
+        // Update the buttons in the picture, so when we draw the picture
+        // to the screen, they are in the correct state.
+        // Tell the native side if user is a) touching the screen,
+        // b) pressing the trackball down, or c) pressing the enter key
+        // If the cursor is on a button, we need to draw it in the pressed
+        // state.
+        // If mNativeClass is 0, we should not reach here, so we do not
+        // need to check it again.
+        nativeRecordButtons(hasFocus() && hasWindowFocus(),
+                mTouchMode == TOUCH_SHORTPRESS_START_MODE
+                || mTrackballDown || mGotCenterDown, false);
+        drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
         canvas.restoreToCount(saveCount);
 
         if (AUTO_REDRAW_HACK && mAutoRedraw) {
@@ -2770,7 +2760,7 @@
                             contentToViewDimension(
                             nativeFocusCandidateTextSize()));
                     Rect bounds = nativeFocusCandidateNodeBounds();
-                    Rect vBox = contentToView(bounds);
+                    Rect vBox = contentToViewRect(bounds);
                     mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
                             vBox.height());
                     // If it is a password field, start drawing the
@@ -2837,371 +2827,6 @@
         }
     }
 
-    private float scrollZoomGridScale(float invScale) {
-        float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
-            / (float) SCROLL_ZOOM_GRID;
-        return 1.0f / griddedInvScale;
-    }
-
-    private float scrollZoomX(float scale) {
-        int width = getViewWidth();
-        float maxScrollZoomX = mContentWidth * scale - width;
-        int maxX = mContentWidth - width;
-        return -(maxScrollZoomX > 0 ? mZoomScrollX * maxScrollZoomX / maxX
-                : maxScrollZoomX / 2);
-    }
-
-    private float scrollZoomY(float scale) {
-        int height = getViewHeight();
-        float maxScrollZoomY = mContentHeight * scale - height;
-        int maxY = mContentHeight - height;
-        return -(maxScrollZoomY > 0 ? mZoomScrollY * maxScrollZoomY / maxY
-                : maxScrollZoomY / 2);
-    }
-
-    private void drawMagnifyFrame(Canvas canvas, Rect frame, Paint paint) {
-        final float ADORNMENT_LEN = 16.0f;
-        float width = frame.width();
-        float height = frame.height();
-        Path path = new Path();
-        path.moveTo(-ADORNMENT_LEN, -ADORNMENT_LEN);
-        path.lineTo(0, 0);
-        path.lineTo(width, 0);
-        path.lineTo(width + ADORNMENT_LEN, -ADORNMENT_LEN);
-        path.moveTo(-ADORNMENT_LEN, height + ADORNMENT_LEN);
-        path.lineTo(0, height);
-        path.lineTo(width, height);
-        path.lineTo(width + ADORNMENT_LEN, height + ADORNMENT_LEN);
-        path.moveTo(0, 0);
-        path.lineTo(0, height);
-        path.moveTo(width, 0);
-        path.lineTo(width, height);
-        path.offset(frame.left, frame.top);
-        canvas.drawPath(path, paint);
-    }
-
-    // Returns frame surrounding magified portion of screen while
-    // scroll-zoom is enabled. The frame is also used to center the
-    // zoom-in zoom-out points at the start and end of the animation.
-    private Rect scrollZoomFrame(int width, int height, float halfScale) {
-        Rect scrollFrame = new Rect();
-        scrollFrame.set(mZoomScrollX, mZoomScrollY,
-                mZoomScrollX + width, mZoomScrollY + height);
-        if (mContentWidth * mZoomScrollLimit < width) {
-            float scale = zoomFrameScaleX(width, halfScale, 1.0f);
-            float offsetX = (width * scale - width) * 0.5f;
-            scrollFrame.left -= offsetX;
-            scrollFrame.right += offsetX;
-        }
-        if (mContentHeight * mZoomScrollLimit < height) {
-            float scale = zoomFrameScaleY(height, halfScale, 1.0f);
-            float offsetY = (height * scale - height) * 0.5f;
-            scrollFrame.top -= offsetY;
-            scrollFrame.bottom += offsetY;
-        }
-        return scrollFrame;
-    }
-
-    private float zoomFrameScaleX(int width, float halfScale, float noScale) {
-        // mContentWidth > width > mContentWidth * mZoomScrollLimit
-        if (mContentWidth <= width) {
-            return halfScale;
-        }
-        float part = (width - mContentWidth * mZoomScrollLimit)
-                / (width * (1 - mZoomScrollLimit));
-        return halfScale * part + noScale * (1.0f - part);
-    }
-
-    private float zoomFrameScaleY(int height, float halfScale, float noScale) {
-        if (mContentHeight <= height) {
-            return halfScale;
-        }
-        float part = (height - mContentHeight * mZoomScrollLimit)
-                / (height * (1 - mZoomScrollLimit));
-        return halfScale * part + noScale * (1.0f - part);
-    }
-
-    private float scrollZoomMagScale(float invScale) {
-        return (invScale * 2 + mInvActualScale) / 3;
-    }
-
-    private void scrollZoomDraw(Canvas canvas) {
-        float invScale = mZoomScrollInvLimit;
-        int elapsed = 0;
-        if (mTouchMode != SCROLL_ZOOM_OUT) {
-            elapsed = (int) Math.min(System.currentTimeMillis()
-                - mZoomScrollStart, SCROLL_ZOOM_DURATION);
-            float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
-                    * elapsed / SCROLL_ZOOM_DURATION;
-            if (mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
-                invScale = mInvActualScale + transitionScale;
-            } else { /* if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) */
-                invScale = mZoomScrollInvLimit - transitionScale;
-            }
-        }
-        float scale = scrollZoomGridScale(invScale);
-        invScale = 1.0f / scale;
-        int width = getViewWidth();
-        int height = getViewHeight();
-        float halfScale = scrollZoomMagScale(invScale);
-        Rect scrollFrame = scrollZoomFrame(width, height, halfScale);
-        if (elapsed == SCROLL_ZOOM_DURATION) {
-            if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
-                setHorizontalScrollBarEnabled(true);
-                setVerticalScrollBarEnabled(true);
-                rebuildWebTextView();
-                scrollTo((int) (scrollFrame.centerX() * mActualScale)
-                        - (width >> 1), (int) (scrollFrame.centerY()
-                        * mActualScale) - (height >> 1));
-                mTouchMode = TOUCH_DONE_MODE;
-                // Show all the child views once we are done.
-                mViewManager.showAll();
-            } else {
-                mTouchMode = SCROLL_ZOOM_OUT;
-            }
-        }
-        float newX = scrollZoomX(scale);
-        float newY = scrollZoomY(scale);
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "scrollZoomDraw scale=" + scale + " + (" + newX
-                    + ", " + newY + ") mZoomScroll=(" + mZoomScrollX + ", "
-                    + mZoomScrollY + ")" + " invScale=" + invScale + " scale="
-                    + scale);
-        }
-        canvas.translate(newX, newY);
-        canvas.scale(scale, scale);
-        boolean animating = mTouchMode != SCROLL_ZOOM_OUT;
-        if (mDrawHistory) {
-            int sc = canvas.save(Canvas.CLIP_SAVE_FLAG);
-            Rect clip = new Rect(0, 0, mHistoryPicture.getWidth(),
-                    mHistoryPicture.getHeight());
-            canvas.clipRect(clip, Region.Op.DIFFERENCE);
-            canvas.drawColor(mBackgroundColor);
-            canvas.restoreToCount(sc);
-            canvas.drawPicture(mHistoryPicture);
-        } else {
-            mWebViewCore.drawContentPicture(canvas, mBackgroundColor,
-                    animating, true);
-        }
-        if (mTouchMode == TOUCH_DONE_MODE) {
-            return;
-        }
-        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        paint.setStyle(Paint.Style.STROKE);
-        paint.setStrokeWidth(30.0f);
-        paint.setARGB(0x50, 0, 0, 0);
-        int maxX = mContentWidth - width;
-        int maxY = mContentHeight - height;
-        if (true) { // experiment: draw hint to place finger off magnify area
-            drawMagnifyFrame(canvas, scrollFrame, paint);
-        } else {
-            canvas.drawRect(scrollFrame, paint);
-        }
-        int sc = canvas.save();
-        canvas.clipRect(scrollFrame);
-        float halfX = (float) mZoomScrollX / maxX;
-        if (mContentWidth * mZoomScrollLimit < width) {
-            halfX = zoomFrameScaleX(width, 0.5f, halfX);
-        }
-        float halfY = (float) mZoomScrollY / maxY;
-        if (mContentHeight * mZoomScrollLimit < height) {
-            halfY = zoomFrameScaleY(height, 0.5f, halfY);
-        }
-        canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX
-                , mZoomScrollY + height * halfY);
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
-                    + width + ", " + height + ") half=(" + halfX + ", "
-                    + halfY + ")");
-        }
-        if (mDrawHistory) {
-            canvas.drawPicture(mHistoryPicture);
-        } else {
-            mWebViewCore.drawContentPicture(canvas, mBackgroundColor,
-                    animating, false);
-        }
-        canvas.restoreToCount(sc);
-        if (mTouchMode != SCROLL_ZOOM_OUT) {
-            invalidate();
-        }
-    }
-
-    private void zoomScrollTap(float x, float y) {
-        float scale = scrollZoomGridScale(mZoomScrollInvLimit);
-        float left = scrollZoomX(scale);
-        float top = scrollZoomY(scale);
-        int width = getViewWidth();
-        int height = getViewHeight();
-        x -= width * scale / 2;
-        y -= height * scale / 2;
-        mZoomScrollX = Math.min(mContentWidth - width
-                , Math.max(0, (int) ((x - left) / scale)));
-        mZoomScrollY = Math.min(mContentHeight - height
-                , Math.max(0, (int) ((y - top) / scale)));
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "zoomScrollTap scale=" + scale + " + (" + left
-                    + ", " + top + ") mZoomScroll=(" + mZoomScrollX + ", "
-                    + mZoomScrollY + ")" + " x=" + x + " y=" + y);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public boolean canZoomScrollOut() {
-        if (mContentWidth == 0 || mContentHeight == 0) {
-            return false;
-        }
-        int width = getViewWidth();
-        int height = getViewHeight();
-        float x = (float) width / (float) mContentWidth;
-        float y = (float) height / (float) mContentHeight;
-        mZoomScrollLimit = Math.max(DEFAULT_MIN_ZOOM_SCALE, Math.min(x, y));
-        mZoomScrollInvLimit = 1.0f / mZoomScrollLimit;
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "canZoomScrollOut"
-                    + " mInvActualScale=" + mInvActualScale
-                    + " mZoomScrollLimit=" + mZoomScrollLimit
-                    + " mZoomScrollInvLimit=" + mZoomScrollInvLimit
-                    + " mContentWidth=" + mContentWidth
-                    + " mContentHeight=" + mContentHeight
-                    );
-        }
-        // don't zoom out unless magnify area is at least half as wide
-        // or tall as content
-        float limit = mZoomScrollLimit * 2;
-        return mContentWidth >= width * limit
-                || mContentHeight >= height * limit;
-    }
-
-    private void startZoomScrollOut() {
-        setHorizontalScrollBarEnabled(false);
-        setVerticalScrollBarEnabled(false);
-        if (getSettings().getBuiltInZoomControls()) {
-            if (mZoomButtonsController.isVisible()) {
-                mZoomButtonsController.setVisible(false);
-            }
-        } else {
-            if (mZoomControlRunnable != null) {
-                mPrivateHandler.removeCallbacks(mZoomControlRunnable);
-            }
-            if (mZoomControls != null) {
-                mZoomControls.hide();
-            }
-        }
-        int width = getViewWidth();
-        int height = getViewHeight();
-        int halfW = width >> 1;
-        mLastTouchX = halfW;
-        int halfH = height >> 1;
-        mLastTouchY = halfH;
-        abortAnimation();
-        mZoomScrollStart = System.currentTimeMillis();
-        Rect zoomFrame = scrollZoomFrame(width, height
-                , scrollZoomMagScale(mZoomScrollInvLimit));
-        mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
-                - (zoomFrame.width() >> 1));
-        mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
-                - (zoomFrame.height() >> 1));
-        scrollTo(0, 0); // triggers inval, starts animation
-        clearTextEntry();
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
-                    + mZoomScrollX + ", " + mZoomScrollY +")");
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public void zoomScrollOut() {
-        if (canZoomScrollOut() == false) {
-            mTouchMode = TOUCH_DONE_MODE;
-            return;
-        }
-        // Hide the child views while in this mode.
-        mViewManager.hideAll();
-        startZoomScrollOut();
-        mTouchMode = SCROLL_ZOOM_ANIMATION_OUT;
-        invalidate();
-    }
-
-    private void moveZoomScrollWindow(float x, float y) {
-        if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
-                && Math.abs(y - mLastZoomScrollRawY) < 1.5f) {
-            return;
-        }
-        mLastZoomScrollRawX = x;
-        mLastZoomScrollRawY = y;
-        int oldX = mZoomScrollX;
-        int oldY = mZoomScrollY;
-        int width = getViewWidth();
-        int height = getViewHeight();
-        int maxZoomX = mContentWidth - width;
-        if (maxZoomX > 0) {
-            int maxScreenX = width - (int) Math.ceil(width
-                    * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
-            if (DebugFlags.WEB_VIEW) {
-                Log.v(LOGTAG, "moveZoomScrollWindow-X"
-                        + " maxScreenX=" + maxScreenX + " width=" + width
-                        + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
-            }
-            x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX;
-            x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit);
-            mZoomScrollX = Math.max(0, Math.min(maxZoomX, (int) x));
-        }
-        int maxZoomY = mContentHeight - height;
-        if (maxZoomY > 0) {
-            int maxScreenY = height - (int) Math.ceil(height
-                    * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
-            if (DebugFlags.WEB_VIEW) {
-                Log.v(LOGTAG, "moveZoomScrollWindow-Y"
-                        + " maxScreenY=" + maxScreenY + " height=" + height
-                        + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
-            }
-            y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY;
-            y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit);
-            mZoomScrollY = Math.max(0, Math.min(maxZoomY, (int) y));
-        }
-        if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
-            invalidate();
-        }
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "moveZoomScrollWindow"
-                    + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
-                    + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
-                    + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
-                    + " last=("+mLastScrollX+", "+mLastScrollY+")"
-                    + " x=" + x + " y=" + y);
-        }
-    }
-
-    private void setZoomScrollIn() {
-        mZoomScrollStart = System.currentTimeMillis();
-    }
-
-    private float mZoomScrollLimit;
-    private float mZoomScrollInvLimit;
-    private int mLastScrollX;
-    private int mLastScrollY;
-    private long mZoomScrollStart;
-    private int mZoomScrollX;
-    private int mZoomScrollY;
-    private float mLastZoomScrollRawX = -1000.0f;
-    private float mLastZoomScrollRawY = -1000.0f;
-    // The zoomed scale varies from 1.0 to DEFAULT_MIN_ZOOM_SCALE == 0.25.
-    // The zoom animation duration SCROLL_ZOOM_DURATION == 0.5.
-    // Two pressures compete for gridding; a high frame rate (e.g. 20 fps)
-    // and minimizing font cache allocations (fewer frames is better).
-    // A SCROLL_ZOOM_GRID of 6 permits about 20 zoom levels over 0.5 seconds:
-    // the inverse of: 1.0, 1.16, 1.33, 1.5, 1.67, 1.84, 2.0, etc. to 4.0
-    private static final int SCROLL_ZOOM_GRID = 6;
-    private static final int SCROLL_ZOOM_DURATION = 500;
-    // Make it easier to get to the bottom of a document by reserving a 32
-    // pixel buffer, for when the starting drag is a bit below the bottom of
-    // the magnify frame.
-    private static final int SCROLL_ZOOM_FINGER_BUFFER = 32;
-
     // draw history
     private boolean mDrawHistory = false;
     private Picture mHistoryPicture = null;
@@ -3311,9 +2936,7 @@
      */
     /* package */ void rebuildWebTextView() {
         // If the WebView does not have focus, do nothing until it gains focus.
-        if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())
-                || (mTouchMode >= FIRST_SCROLL_ZOOM
-                && mTouchMode <= LAST_SCROLL_ZOOM)) {
+        if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) {
             return;
         }
         boolean alreadyThere = inEditingMode();
@@ -3364,7 +2987,7 @@
                 Selection.setSelection(spannable, start, end);
             }
         } else {
-            Rect vBox = contentToView(bounds);
+            Rect vBox = contentToViewRect(bounds);
             mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
                     vBox.height());
             mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
@@ -3478,11 +3101,9 @@
 
         // Bubble up the key event if
         // 1. it is a system key; or
-        // 2. the host application wants to handle it; or
-        // 3. webview is in scroll-zoom state;
+        // 2. the host application wants to handle it;
         if (event.isSystem()
-                || mCallbackProxy.uiOverrideKeyEvent(event)
-                || (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM)) {
+                || mCallbackProxy.uiOverrideKeyEvent(event)) {
             return false;
         }
 
@@ -3629,18 +3250,6 @@
             return false;
         }
 
-        // special handling in scroll_zoom state
-        if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
-            if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode
-                    && mTouchMode != SCROLL_ZOOM_ANIMATION_IN) {
-                setZoomScrollIn();
-                mTouchMode = SCROLL_ZOOM_ANIMATION_IN;
-                invalidate();
-                return true;
-            }
-            return false;
-        }
-
         if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
                 || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
             if (commitCopy()) {
@@ -3961,11 +3570,8 @@
         }
 
         // pass the touch events from UI thread to WebCore thread
-        if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT
-                && mTouchMode != SCROLL_ZOOM_ANIMATION_IN
-                && mTouchMode != SCROLL_ZOOM_ANIMATION_OUT
-                && (action != MotionEvent.ACTION_MOVE ||
-                        eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
+        if (mForwardTouchEvents && (action != MotionEvent.ACTION_MOVE
+                || eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
             WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
             ted.mAction = action;
             ted.mX = viewToContentX((int) x + mScrollX);
@@ -3979,15 +3585,7 @@
 
         switch (action) {
             case MotionEvent.ACTION_DOWN: {
-                if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN
-                        || mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
-                    // no interaction while animation is in progress
-                    break;
-                } else if (mTouchMode == SCROLL_ZOOM_OUT) {
-                    mLastScrollX = mZoomScrollX;
-                    mLastScrollY = mZoomScrollY;
-                    // If two taps are close, ignore the first tap
-                } else if (!mScroller.isFinished()) {
+                if (!mScroller.isFinished()) {
                     // stop the current scroll animation, but if this is
                     // the start of a fling, allow it to add to the current
                     // fling's velocity
@@ -4038,17 +3636,10 @@
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                if (mTouchMode == TOUCH_DONE_MODE
-                        || mTouchMode == SCROLL_ZOOM_ANIMATION_IN
-                        || mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
+                if (mTouchMode == TOUCH_DONE_MODE) {
                     // no dragging during scroll zoom animation
                     break;
                 }
-                if (mTouchMode == SCROLL_ZOOM_OUT) {
-                    // while fully zoomed out, move the virtual window
-                    moveZoomScrollWindow(x, y);
-                    break;
-                }
                 mVelocityTracker.addMovement(ev);
 
                 if (mTouchMode != TOUCH_DRAG_MODE) {
@@ -4096,8 +3687,7 @@
                     if (settings.supportZoom()
                             && settings.getBuiltInZoomControls()
                             && !mZoomButtonsController.isVisible()
-                            && (canZoomScrollOut() ||
-                                    mMinZoomScale < mMaxZoomScale)) {
+                            && mMinZoomScale < mMaxZoomScale) {
                         mZoomButtonsController.setVisible(true);
                     }
                 }
@@ -4164,12 +3754,11 @@
 
                 if (!getSettings().getBuiltInZoomControls()) {
                     boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
-                    boolean showMagnify = canZoomScrollOut();
-                    if (mZoomControls != null && (showPlusMinus || showMagnify)) {
+                    if (mZoomControls != null && showPlusMinus) {
                         if (mZoomControls.getVisibility() == View.VISIBLE) {
                             mPrivateHandler.removeCallbacks(mZoomControlRunnable);
                         } else {
-                            mZoomControls.show(showPlusMinus, showMagnify);
+                            mZoomControls.show(showPlusMinus, false);
                         }
                         mPrivateHandler.postDelayed(mZoomControlRunnable,
                                 ZOOM_CONTROLS_TIMEOUT);
@@ -4192,17 +3781,14 @@
                         doDoubleTap();
                         break;
                     case TOUCH_INIT_MODE: // tap
-                        if (ENABLE_DOUBLETAP_ZOOM) {
-                            mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
-                            if (!mPreventDrag) {
-                                mPrivateHandler.sendMessageDelayed(
-                                        mPrivateHandler.obtainMessage(
-                                        RELEASE_SINGLE_TAP),
-                                        ViewConfiguration.getDoubleTapTimeout());
-                            }
-                            break;
+                        mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+                        if (!mPreventDrag) {
+                            mPrivateHandler.sendMessageDelayed(
+                                    mPrivateHandler.obtainMessage(
+                                    RELEASE_SINGLE_TAP),
+                                    ViewConfiguration.getDoubleTapTimeout());
                         }
-                        // fall through
+                        break;
                     case TOUCH_SHORTPRESS_START_MODE:
                     case TOUCH_SHORTPRESS_MODE:
                         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
@@ -4214,28 +3800,6 @@
                         commitCopy();
                         mTouchSelection = false;
                         break;
-                    case SCROLL_ZOOM_ANIMATION_IN:
-                    case SCROLL_ZOOM_ANIMATION_OUT:
-                        // no action during scroll animation
-                        break;
-                    case SCROLL_ZOOM_OUT:
-                        if (DebugFlags.WEB_VIEW) {
-                            Log.v(LOGTAG, "ACTION_UP SCROLL_ZOOM_OUT"
-                                    + " eventTime - mLastTouchTime="
-                                    + (eventTime - mLastTouchTime));
-                        }
-                        // for now, always zoom back when the drag completes
-                        if (true || eventTime - mLastTouchTime < TAP_TIMEOUT) {
-                            // but if we tap, zoom in where we tap
-                            if (eventTime - mLastTouchTime < TAP_TIMEOUT) {
-                                zoomScrollTap(x, y);
-                            }
-                            // start zooming in back to the original view
-                            setZoomScrollIn();
-                            mTouchMode = SCROLL_ZOOM_ANIMATION_IN;
-                            invalidate();
-                        }
-                        break;
                     case TOUCH_DRAG_MODE:
                         // if the user waits a while w/o moving before the
                         // up, we don't want to do a fling
@@ -4269,10 +3833,7 @@
                     mVelocityTracker.recycle();
                     mVelocityTracker = null;
                 }
-                if (mTouchMode == SCROLL_ZOOM_OUT ||
-                        mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
-                    scrollTo(mZoomScrollX, mZoomScrollY);
-                } else if (mTouchMode == TOUCH_DRAG_MODE) {
+                if (mTouchMode == TOUCH_DRAG_MODE) {
                     WebViewCore.resumeUpdate(mWebViewCore);
                 }
                 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
@@ -4371,11 +3932,6 @@
             if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit");
             return false;
         }
-        // no move if we're still waiting on SWITCH_TO_CLICK timeout
-        if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
-            if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
-            return true;
-        }
         if (mTrackballDown) {
             if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit");
             return true; // discard move if trackball is down
@@ -4511,25 +4067,6 @@
         int height = mContentHeight - getViewHeight();
         if (width < 0) width = 0;
         if (height < 0) height = 0;
-        if (mTouchMode == SCROLL_ZOOM_OUT) {
-            int oldX = mZoomScrollX;
-            int oldY = mZoomScrollY;
-            int maxWH = Math.max(width, height);
-            mZoomScrollX += scaleTrackballX(xRate, maxWH);
-            mZoomScrollY += scaleTrackballY(yRate, maxWH);
-            if (DebugFlags.WEB_VIEW) {
-                Log.v(LOGTAG, "doTrackball SCROLL_ZOOM_OUT"
-                        + " mZoomScrollX=" + mZoomScrollX
-                        + " mZoomScrollY=" + mZoomScrollY);
-            }
-            mZoomScrollX = Math.min(width, Math.max(0, mZoomScrollX));
-            mZoomScrollY = Math.min(height, Math.max(0, mZoomScrollY));
-            if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
-                invalidate();
-            }
-            mTrackballRemainsX = mTrackballRemainsY = 0;
-            return;
-        }
         ax = Math.abs(mTrackballRemainsX * TRACKBALL_MULTIPLIER);
         ay = Math.abs(mTrackballRemainsY * TRACKBALL_MULTIPLIER);
         maxA = Math.max(ax, ay);
@@ -4749,14 +4286,6 @@
                 zoomOut();
             }
         });
-        zoomControls.setOnZoomMagnifyClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                mPrivateHandler.removeCallbacks(mZoomControlRunnable);
-                mPrivateHandler.postDelayed(mZoomControlRunnable,
-                        ZOOM_CONTROLS_TIMEOUT);
-                zoomScrollOut();
-            }
-        });
         return zoomControls;
     }
 
@@ -4801,7 +4330,7 @@
         // TODO: alternatively we can disallow this during draw history mode
         switchOutDrawHistory();
         float scale = mActualScale * 0.8f;
-        if (scale < (mMinZoomScale + 0.1f) && WebView.ENABLE_DOUBLETAP_ZOOM
+        if (scale < (mMinZoomScale + 0.1f)
                 && mWebViewCore.getSettings().getUseWideViewPort()) {
             // when zoom out to min scale, switch to overview mode
             doDoubleTap();
@@ -4888,6 +4417,9 @@
         // In case the soft keyboard has been dismissed, bring it back up.
         InputMethodManager.getInstance(getContext()).showSoftInput(mWebTextView,
                 0);
+        if (nativeFocusNodePointer() != nativeCursorNodePointer()) {
+            nativeMotionUp(x, y, mNavSlop);
+        }
         nativeTextInputMotionUp(x, y);
     }
 
@@ -5258,7 +4790,7 @@
                         setNewZoomScale(mLastScale, false);
                         setContentScrollTo(restoreState.mScrollX,
                                 restoreState.mScrollY);
-                        if (ENABLE_DOUBLETAP_ZOOM && useWideViewport
+                        if (useWideViewport
                                 && settings.getLoadWithOverviewMode()) {
                             if (restoreState.mViewScale == 0
                                     || (restoreState.mMobileSite
@@ -5285,7 +4817,7 @@
                         Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
                                 b.left+","+b.top+","+b.right+","+b.bottom+"}");
                     }
-                    invalidate(contentToView(draw.mInvalRegion.getBounds()));
+                    invalidateContentRect(draw.mInvalRegion.getBounds());
                     if (mPictureListener != null) {
                         mPictureListener.onNewPicture(WebView.this, capturePicture());
                     }
@@ -5744,7 +5276,7 @@
         // FIXME the divisor should be retrieved from somewhere
         // the closest thing today is hard-coded into ScrollView.java
         // (from ScrollView.java, line 363)   int maxJump = height/2;
-        return viewToContentY(height);
+        return Math.round(height * mInvActualScale);
     }
 
     /**
@@ -5784,7 +5316,7 @@
         }
         Rect contentCursorRingBounds = nativeGetCursorRingBounds();
         if (contentCursorRingBounds.isEmpty()) return keyHandled;
-        Rect viewCursorRingBounds = contentToView(contentCursorRingBounds);
+        Rect viewCursorRingBounds = contentToViewRect(contentCursorRingBounds);
         Rect visRect = new Rect();
         calcOurVisibleRect(visRect);
         Rect outset = new Rect(visRect);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 26d9343..799312d 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -37,7 +37,6 @@
 
 import java.util.ArrayList;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 
 import junit.framework.Assert;
@@ -1528,9 +1527,6 @@
     // Used to suspend drawing.
     private boolean mDrawIsPaused;
 
-    // Used to end scale+scroll mode, accessed by both threads
-    boolean mEndScaleZoom = false;
-
     // mRestoreState is set in didFirstLayout(), and reset in the next
     // webkitDraw after passing it to the UI thread.
     private RestoreState mRestoreState = null;
@@ -1571,7 +1567,7 @@
             // Send the native view size that was used during the most recent
             // layout.
             draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
-            if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
+            if (mSettings.getUseWideViewPort()) {
                 draw.mMinPrefWidth = Math.max(
                         mViewportWidth == -1 ? DEFAULT_VIEWPORT_WIDTH
                                 : (mViewportWidth == 0 ? mCurrentViewWidth
@@ -1977,7 +1973,7 @@
 
     // called by JNI
     private void restoreScreenWidthScale(int scale) {
-        if (!WebView.ENABLE_DOUBLETAP_ZOOM || !mSettings.getUseWideViewPort()) {
+        if (!mSettings.getUseWideViewPort()) {
             return;
         }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 2f292d5..b242b58 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2945,10 +2945,16 @@
             okToSend = false;
             break;
         case KeyEvent.KEYCODE_BACK:
-            if (mFiltered && mPopup != null && mPopup.isShowing() &&
-                    event.getAction() == KeyEvent.ACTION_DOWN) {
-                handled = true;
-                mTextFilter.setText("");
+            if (mFiltered && mPopup != null && mPopup.isShowing()) {
+                if (event.getAction() == KeyEvent.ACTION_DOWN
+                        && event.getRepeatCount() == 0) {
+                    getKeyDispatcherState().startTracking(event, this);
+                    handled = true;
+                } else if (event.getAction() == KeyEvent.ACTION_UP
+                        && event.isTracking() && !event.isCanceled()) {
+                    handled = true;
+                    mTextFilter.setText("");
+                }
             }
             okToSend = false;
             break;
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 2a0e5e5..d25530b 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -301,11 +301,16 @@
                 trackTouchEvent(event);
                 onStopTrackingTouch();
                 setPressed(false);
+                // ProgressBar doesn't know to repaint the thumb drawable
+                // in its inactive state when the touch stops (because the
+                // value has not apparently changed)
+                invalidate();
                 break;
                 
             case MotionEvent.ACTION_CANCEL:
                 onStopTrackingTouch();
                 setPressed(false);
+                invalidate(); // see above explanation
                 break;
         }
         return true;
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index d821a7d..4566c4c 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -603,10 +603,16 @@
 
     @Override
     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
-        if (isPopupShowing()) {
+        if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing()
+                && !mDropDownAlwaysVisible) {
             // special case for the back key, we do not even try to send it
             // to the drop down list but instead, consume it immediately
-            if (keyCode == KeyEvent.KEYCODE_BACK && !mDropDownAlwaysVisible) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN
+                    && event.getRepeatCount() == 0) {
+                getKeyDispatcherState().startTracking(event, this);
+                return true;
+            } else if (event.getAction() == KeyEvent.ACTION_UP
+                    && event.isTracking() && !event.isCanceled()) {
                 dismissDropDown();
                 return true;
             }
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index e7b303a..f34823c 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -23,7 +23,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Config;
 import android.util.Log;
 import android.view.GestureDetector;
 import android.view.Gravity;
@@ -36,8 +35,6 @@
 import android.view.SoundEffectConstants;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.animation.Transformation;
-import android.widget.AbsSpinner;
-import android.widget.Scroller;
 
 /**
  * A view that shows items in a center-locked, horizontally scrolling list.
@@ -59,7 +56,7 @@
 
     private static final String TAG = "Gallery";
 
-    private static final boolean localLOGV = Config.LOGV;
+    private static final boolean localLOGV = false;
 
     /**
      * Duration in milliseconds from the start of a scroll during which we're
@@ -514,6 +511,7 @@
             // We haven't been callbacking during the fling, so do it now
             super.selectionChanged();
         }
+        invalidate();
     }
     
     @Override
@@ -534,12 +532,9 @@
         
         int galleryCenter = getCenterOfGallery();
         
-        if (selView != null) {
-
-            // Common case where the current selected position is correct
-            if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
-                return;
-            }
+        // Common case where the current selected position is correct
+        if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
+            return;
         }
         
         // TODO better search
@@ -627,7 +622,6 @@
         View sel = makeAndAddView(mSelectedPosition, 0, 0, true);
         
         // Put the selected child in the center
-        Gallery.LayoutParams lp = (Gallery.LayoutParams) sel.getLayoutParams();
         int selectedOffset = childrenLeft + (childrenWidth / 2) - (sel.getWidth() / 2);
         sel.offsetLeftAndRight(selectedOffset);
 
@@ -733,9 +727,6 @@
             child = mRecycler.get(position);
             if (child != null) {
                 // Can reuse an existing view
-                Gallery.LayoutParams lp = (Gallery.LayoutParams) 
-                    child.getLayoutParams();
-
                 int childLeft = child.getLeft();
                 
                 // Remember left and right edges of where views have been placed
@@ -798,7 +789,7 @@
         int childRight;
 
         // Position vertically based on gravity setting
-        int childTop = calculateTop(child, lp, true);
+        int childTop = calculateTop(child, true);
         int childBottom = childTop + child.getMeasuredHeight();
 
         int width = child.getMeasuredWidth();
@@ -817,11 +808,9 @@
      * Figure out vertical placement based on mGravity
      * 
      * @param child Child to place
-     * @param lp LayoutParams for this view (just so we don't keep looking them
-     *        up)
      * @return Where the top of the child should be
      */
-    private int calculateTop(View child, Gallery.LayoutParams lp, boolean duringLayout) {
+    private int calculateTop(View child, boolean duringLayout) {
         int myHeight = duringLayout ? mMeasuredHeight : getHeight();
         int childHeight = duringLayout ? child.getMeasuredHeight() : child.getHeight(); 
         
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 548dee9..d86b674 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1323,8 +1323,16 @@
         @Override
         public boolean dispatchKeyEvent(KeyEvent event) {
             if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-                dismiss();
-                return true;
+                if (event.getAction() == KeyEvent.ACTION_DOWN
+                        && event.getRepeatCount() == 0) {
+                    getKeyDispatcherState().startTracking(event, this);
+                    return true;
+                } else if (event.getAction() == KeyEvent.ACTION_UP
+                        && event.isTracking() && !event.isCanceled()) {
+                    dismiss();
+                    return true;
+                }
+                return super.dispatchKeyEvent(event);
             } else {
                 return super.dispatchKeyEvent(event);
             }
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index a41e2e3..760b8ff 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -476,7 +476,21 @@
         if (isInterestingKey(keyCode)) {
 
             if (keyCode == KeyEvent.KEYCODE_BACK) {
-                setVisible(false);
+                if (event.getAction() == KeyEvent.ACTION_DOWN
+                        && event.getRepeatCount() == 0) {
+                    if (mOwnerView != null) {
+                        KeyEvent.DispatcherState ds = mOwnerView.getKeyDispatcherState();
+                        if (ds != null) {
+                            ds.startTracking(event, this);
+                        }
+                    }
+                    return true;
+                } else if (event.getAction() == KeyEvent.ACTION_UP
+                        && event.isTracking() && !event.isCanceled()) {
+                    setVisible(false);
+                    return true;
+                }
+                
             } else {
                 dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
             }
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 5825024..35b9251 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -57,6 +57,13 @@
         mCallback = callback;
     }
 
+    public HandlerCaller(Context context, Looper looper, Callback callback) {
+        mContext = context;
+        mMainLooper = looper;
+        mH = new MyHandler(mMainLooper);
+        mCallback = callback;
+    }
+
     public SomeArgs obtainArgs() {
         synchronized (mH) {
             SomeArgs args = mArgsPool;
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index 5357469..0bc70de 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -20,6 +20,8 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.HandlerThread;
+import android.os.Process;
 import android.service.wallpaper.WallpaperService;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
@@ -33,20 +35,29 @@
  */
 public class ImageWallpaper extends WallpaperService {
     WallpaperManager mWallpaperManager;
+    private HandlerThread mThread;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
+        mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
+        mThread.start();
+        setCallbackLooper(mThread.getLooper());
     }
 
     public Engine onCreateEngine() {
         return new DrawableEngine();
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mThread.quit();
+    }
+
     class DrawableEngine extends Engine {
         private final Object mLock = new Object();
-        private final Rect mBounds = new Rect();
         private WallpaperObserver mReceiver;
         Drawable mBackground;
         float mXOffset;
@@ -56,6 +67,9 @@
             public void onReceive(Context context, Intent intent) {
                 updateWallpaper();
                 drawFrame();
+                // Assume we are the only one using the wallpaper in this
+                // process, and force a GC now to release the old wallpaper.
+                System.gc();
             }
         }
 
@@ -67,7 +81,6 @@
             registerReceiver(mReceiver, filter);
             updateWallpaper();
             surfaceHolder.setSizeFromLayout();
-            //setTouchEventsEnabled(true);
         }
 
         @Override
@@ -137,11 +150,7 @@
 
         void updateWallpaper() {
             synchronized (mLock) {
-                mBackground = mWallpaperManager.getDrawable();
-                mBounds.left = mBounds.top = 0;
-                mBounds.right = mBackground.getIntrinsicWidth();
-                mBounds.bottom = mBackground.getIntrinsicHeight();
-                mBackground.setBounds(mBounds);
+                mBackground = mWallpaperManager.getFastDrawable();
             }
         }
     }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index f4f6297..b8d19ac 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -90,6 +90,12 @@
     public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
     }
     
-    public void dispatchWallpaperOffsets(float x, float y) {
+    public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
+        if (sync) {
+            try {
+                mSession.wallpaperOffsetsComplete(asBinder());
+            } catch (RemoteException e) {
+            }
+        }
     }
 }
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index b81c2b3..bba2ee2 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -282,7 +282,9 @@
         itemView.setIconMenuView(this);
         
         // Apply the background to the item view
-        itemView.setBackgroundDrawable(mItemBackground.getConstantState().newDrawable());
+        itemView.setBackgroundDrawable(
+                mItemBackground.getConstantState().newDrawable(
+                        getContext().getResources()));
 
         // This class is the invoker for all its item views 
         itemView.setItemInvoker(this);
diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
index 88f7b2f..70f040a 100644
--- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
@@ -22,6 +22,7 @@
 import android.os.IBinder;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.Window;
 import android.view.WindowManager;
 import android.widget.ListAdapter;
 
@@ -86,18 +87,26 @@
     }
     
     public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
-        /*
-         * Close menu on key down (more responsive, and there's no way to cancel
-         * a key press so no point having it on key up. Note: This is also
-         * needed because when a top-level menu item that shows a submenu is
-         * invoked by chording, this onKey method will be called with the menu
-         * up event.
-         */
-        if (event.getAction() == KeyEvent.ACTION_DOWN && (keyCode == KeyEvent.KEYCODE_MENU)
-                || (keyCode == KeyEvent.KEYCODE_BACK)) {
-            mMenu.close(true);
-            dialog.dismiss();
-            return true;
+        if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_BACK) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN
+                    && event.getRepeatCount() == 0) {
+                Window win = mDialog.getWindow();
+                if (win != null) {
+                    View decor = win.getDecorView();
+                    if (decor != null) {
+                        KeyEvent.DispatcherState ds = decor.getKeyDispatcherState();
+                        if (ds != null) {
+                            ds.startTracking(event, this);
+                            return true;
+                        }
+                    }
+                }
+            } else if (event.getAction() == KeyEvent.ACTION_UP
+                    && event.isTracking() && !event.isCanceled()) {
+                mMenu.close(true);
+                dialog.dismiss();
+                return true;
+            }
         }
 
         // Menu shortcut matching
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 8a312d9..ce2b10c 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -327,6 +327,18 @@
     }
 }
 
+static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz)
+{
+    LOGV("cancelAutoFocus");
+    JNICameraContext* context;
+    sp<Camera> c = get_native_camera(env, thiz, &context);
+    if (c == 0) return;
+
+    if (c->cancelAutoFocus() != NO_ERROR) {
+        jniThrowException(env, "java/lang/RuntimeException", "cancelAutoFocus failed");
+    }
+}
+
 static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
 {
     LOGV("takePicture");
@@ -422,6 +434,9 @@
   { "native_autoFocus",
     "()V",
     (void *)android_hardware_Camera_autoFocus },
+  { "native_cancelAutoFocus",
+    "()V",
+    (void *)android_hardware_Camera_cancelAutoFocus },
   { "native_takePicture",
     "()V",
     (void *)android_hardware_Camera_takePicture },
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7748aba..5b6c7ea 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -32,6 +32,7 @@
 #include <sys/errno.h>
 #include <sys/resource.h>
 #include <sys/types.h>
+#include <cutils/sched_policy.h>
 #include <dirent.h>
 #include <fcntl.h>
 #include <grp.h>
@@ -186,58 +187,6 @@
     return -1;
 }
 
-static int add_pid_to_cgroup(int pid, const char *grp_name)
-{
-    int fd;
-    char path[255];
-    char text[64];
-
-    sprintf(path, "/dev/cpuctl/%s/tasks", grp_name);
-
-    if ((fd = open(path, O_WRONLY)) < 0)
-        return -1;
-
-    sprintf(text, "%d", pid);
-    if (write(fd, text, strlen(text)) < 0) {
-        close(fd);
-        return -1;
-    }
-
-    close(fd);
-    return 0;
-}
-
-void setSchedPolicy(JNIEnv* env, jobject clazz, int pid, SchedPolicy policy)
-{
-    static int __sys_supports_schedgroups = -1;
-
-    if (__sys_supports_schedgroups < 0) {
-        if (!access("/dev/cpuctl/tasks", F_OK)) {
-            __sys_supports_schedgroups = 1;
-        } else {
-            __sys_supports_schedgroups = 0;
-        }
-    }
-
-    if (__sys_supports_schedgroups) {
-        const char *grp = NULL;
-
-        if (policy == SP_BACKGROUND) {
-            grp = "bg_non_interactive";
-        }
-
-        if (add_pid_to_cgroup(pid, grp)) {
-            if (errno != ESRCH && errno != ENOENT)
-                signalExceptionForGroupError(env, clazz, errno);
-        }
-    } else {
-        struct sched_param param;
-
-        param.sched_priority = 0;
-        sched_setscheduler(pid, (policy == SP_BACKGROUND) ? 5 : 0, &param);
-    }
-}
-
 void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
 {
     if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
@@ -245,9 +194,10 @@
         return;
     }
 
-    setSchedPolicy(env, clazz, pid,
-                   (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
-                           SP_BACKGROUND : SP_FOREGROUND);
+    if (set_sched_policy(pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                                      SP_BACKGROUND : SP_FOREGROUND)) {
+        signalExceptionForGroupError(env, clazz, errno);
+    }
 }
 
 void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp) 
@@ -291,9 +241,10 @@
             continue;
         }
      
-        setSchedPolicy(env, clazz, t_pid,
-                       (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
-                               SP_BACKGROUND : SP_FOREGROUND);
+        if (set_sched_policy(t_pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                                            SP_BACKGROUND : SP_FOREGROUND)) {
+            signalExceptionForGroupError(env, clazz, errno);
+        }
     }
     closedir(d);
 }
@@ -301,10 +252,16 @@
 void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
                                               jint pid, jint pri)
 {
+    int rc = 0;
+
     if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-        setSchedPolicy(env, clazz, pid, SP_BACKGROUND);
+        rc = set_sched_policy(pid, SP_BACKGROUND);
     } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
-        setSchedPolicy(env, clazz, pid, SP_FOREGROUND);
+        rc = set_sched_policy(pid, SP_FOREGROUND);
+    }
+
+    if (rc) {
+        signalExceptionForGroupError(env, clazz, errno);
     }
 
     if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d1cb0bd..568ed92 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2843,9 +2843,7 @@
              is also used as an icon to the left of the search box and you cannot modify this
              behavior, so including the icon attribute is unecessary and this may be
              deprecated in the future.
-             <i>Optional attribute.</i>
-             {@deprecated This will create a non-standard UI appearance, because the search bar UI
-              now puts the activity or application icon beside the search box.} -->
+             <i>Optional attribute.</i> -->
         <attr name="icon" />
         <!-- This is the user-displayed name of the searchable activity.  <i>Required
             attribute.</i> -->
@@ -2870,10 +2868,7 @@
           <flag name="showSearchLabelAsBadge" value="0x04" />
           <!-- If set, this flag enables the display of the search target (icon) within the
                search bar.  (Note, overrides showSearchLabel)  If neither bad mode is selected,
-               no badge will be shown.
-              {@deprecated This will create a non-standard UI appearance, because the search bar UI
-              now puts the activity or application icon beside the search box.}
-               -->
+               no badge will be shown.-->
           <flag name="showSearchIconAsBadge" value="0x08" />
           <!-- If set, this flag causes the suggestion column SUGGEST_COLUMN_INTENT_DATA to
                be considered as the text for suggestion query rewriting.  This should only
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index abb575c..117e139 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -81,4 +81,6 @@
         <item>30</item>
     </integer-array>
     
+    <!-- Flag indicating whether the device supports automatic brightness mode. -->
+    <bool name="config_automatic_brightness_available">false</bool>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0902c21..69ddd63 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -234,7 +234,7 @@
     supply an auth token without prompting the user to re-enter the
     password.  This is the text that will scroll through the
     notification bar (will be seen by the user as he uses another application). -->
-    <string name="notification_title">Sign-in error</string>
+    <string name="notification_title">Sign-in error for <xliff:g id="account" example="foo@gmail.com">%1$s</xliff:g></string>
 
     <!-- Sync notifications --> <skip />
     <!-- A notification is shown when there is a sync error.  This is the text that will scroll through the notification bar (will be seen by the user as he uses another application). -->
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index ac96f20..58206d4 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -45,11 +45,11 @@
     private boolean mRunning;
 
     public AnimatedRotateDrawable() {
-        this(null);
+        this(null, null);
     }
 
-    private AnimatedRotateDrawable(AnimatedRotateState rotateState) {
-        mState = new AnimatedRotateState(rotateState, this);
+    private AnimatedRotateDrawable(AnimatedRotateState rotateState, Resources res) {
+        mState = new AnimatedRotateState(rotateState, this, res);
         init();
     }
 
@@ -296,9 +296,14 @@
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;        
 
-        public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner) {
+        public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner,
+                Resources res) {
             if (source != null) {
-                mDrawable = source.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mPivotXRel = source.mPivotXRel;
                 mPivotX = source.mPivotX;
@@ -312,7 +317,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new AnimatedRotateDrawable(this);
+            return new AnimatedRotateDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimatedRotateDrawable(this, res);
         }
         
         @Override
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 68718c9..fdc4c92 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -77,7 +77,7 @@
     private boolean mMutated;
 
     public AnimationDrawable() {
-        this(null);
+        this(null, null);
     }
 
     @Override
@@ -297,8 +297,9 @@
         private int[] mDurations;
         private boolean mOneShot;
 
-        AnimationState(AnimationState orig, AnimationDrawable owner) {
-            super(orig, owner);
+        AnimationState(AnimationState orig, AnimationDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
 
             if (orig != null) {
                 mDurations = orig.mDurations;
@@ -311,7 +312,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new AnimationDrawable(this);
+            return new AnimationDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimationDrawable(this, res);
         }
 
         public void addFrame(Drawable dr, int dur) {
@@ -330,8 +336,8 @@
         }
     }
 
-    private AnimationDrawable(AnimationState state) {
-        AnimationState as = new AnimationState(state, this);
+    private AnimationDrawable(AnimationState state, Resources res) {
+        AnimationState as = new AnimationState(state, this, res);
         mAnimationState = as;
         setConstantState(as);
         if (state != null) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 30cef67..e82f297 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -60,15 +60,15 @@
             Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
     private BitmapState mBitmapState;
     private Bitmap mBitmap;
+    private int mTargetDensity;
+
     private final Rect mDstRect = new Rect();   // Gravity.apply() sets this
 
     private boolean mApplyGravity;
     private boolean mRebuildShader;
     private boolean mMutated;
     
-    private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
-
-    // These are scaled to match the target density.
+     // These are scaled to match the target density.
     private int mBitmapWidth;
     private int mBitmapHeight;
     
@@ -88,10 +88,7 @@
      */
     public BitmapDrawable(Resources res) {
         mBitmapState = new BitmapState((Bitmap) null);
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mBitmapState.mTargetDensity = mTargetDensity;
-        }
+        mBitmapState.mTargetDensity = mTargetDensity;
     }
 
     /**
@@ -101,7 +98,7 @@
      */
     @Deprecated
     public BitmapDrawable(Bitmap bitmap) {
-        this(new BitmapState(bitmap));
+        this(new BitmapState(bitmap), null);
     }
 
     /**
@@ -109,22 +106,51 @@
      * the display metrics of the resources.
      */
     public BitmapDrawable(Resources res, Bitmap bitmap) {
-        this(new BitmapState(bitmap));
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mBitmapState.mTargetDensity = mTargetDensity;
-        }
+        this(new BitmapState(bitmap), res);
+        mBitmapState.mTargetDensity = mTargetDensity;
     }
 
+    /**
+     * Create a drawable by opening a given file path and decoding the bitmap.
+     * @deprecated Use {@link #BitmapDrawable(Resources, String)} to ensure
+     * that the drawable has correctly set its target density.
+     */
     public BitmapDrawable(String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)));
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
     }
 
+    /**
+     * Create a drawable by opening a given file path and decoding the bitmap.
+     */
+    public BitmapDrawable(Resources res, String filepath) {
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
+        mBitmapState.mTargetDensity = mTargetDensity;
+        if (mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+        }
+    }
+
+    /**
+     * Create a drawable by decoding a bitmap from the given input stream.
+     * @deprecated Use {@link #BitmapDrawable(Resources, java.io.InputStream)} to ensure
+     * that the drawable has correctly set its target density.
+     */
     public BitmapDrawable(java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)));
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+        if (mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+        }
+    }
+
+    /**
+     * Create a drawable by decoding a bitmap from the given input stream.
+     */
+    public BitmapDrawable(Resources res, java.io.InputStream is) {
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+        mBitmapState.mTargetDensity = mTargetDensity;
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
@@ -425,7 +451,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new BitmapDrawable(this);
+            return new BitmapDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new BitmapDrawable(this, res);
         }
         
         @Override
@@ -434,9 +465,15 @@
         }
     }
 
-    private BitmapDrawable(BitmapState state) {
+    private BitmapDrawable(BitmapState state, Resources res) {
         mBitmapState = state;
-        mTargetDensity = state.mTargetDensity;
+        if (res != null) {
+            mTargetDensity = res.getDisplayMetrics().densityDpi;
+        } else if (state != null) {
+            mTargetDensity = state.mTargetDensity;
+        } else {
+            mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+        }
         setBitmap(state.mBitmap);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 95d4dd0..c387a9b 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -48,14 +48,14 @@
     public static final int VERTICAL = 2;
     
     ClipDrawable() {
-        this(null);
+        this(null, null);
     }
 
     /**
      * @param orientation Bitwise-or of {@link #HORIZONTAL} and/or {@link #VERTICAL}
      */
     public ClipDrawable(Drawable drawable, int gravity, int orientation) {
-        this(null);
+        this(null, null);
 
         mClipState.mDrawable = drawable;
         mClipState.mGravity = gravity;
@@ -241,9 +241,13 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
-        ClipState(ClipState orig, ClipDrawable owner) {
+        ClipState(ClipState orig, ClipDrawable owner, Resources res) {
             if (orig != null) {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mOrientation = orig.mOrientation;
                 mGravity = orig.mGravity;
@@ -253,7 +257,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new ClipDrawable(this);
+            return new ClipDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new ClipDrawable(this, res);
         }
 
         @Override
@@ -271,8 +280,8 @@
         }
     }
 
-    private ClipDrawable(ClipState state) {
-        mClipState = new ClipState(state, this);
+    private ClipDrawable(ClipState state, Resources res) {
+        mClipState = new ClipState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 226cc04..604c602 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -146,6 +146,11 @@
         }
 
         @Override
+        public Drawable newDrawable(Resources res) {
+            return new ColorDrawable(this);
+        }
+
+        @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 21b5e39..6a7b2d1 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -822,7 +822,26 @@
     }
 
     public static abstract class ConstantState {
+        /**
+         * Create a new drawable without supplying resources the caller
+         * is running in.  Note that using this means the density-dependent
+         * drawables (like bitmaps) will not be able to update their target
+         * density correctly.
+         */
         public abstract Drawable newDrawable();
+        /**
+         * Create a new Drawable instance from its constant state.  This
+         * must be implemented for drawables that change based on the target
+         * density of their caller (that is depending on whether it is
+         * in compatibility mode).
+         */
+        public Drawable newDrawable(Resources res) {
+            return newDrawable();
+        }
+        /**
+         * Return a bit mask of configuration changes that will impact
+         * this drawable (and thus require completely reloading it).
+         */
         public abstract int getChangingConfigurations();
     }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index af1a289..3266f1e 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.content.res.Resources;
 import android.graphics.*;
 
 public class DrawableContainer extends Drawable implements Drawable.Callback {
@@ -285,7 +286,8 @@
 
         boolean     mPaddingChecked = false;
 
-        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner) {
+        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
+                Resources res) {
             mOwner = owner;
 
             if (orig != null) {
@@ -299,7 +301,11 @@
 
                 final int N = mNumChildren;
                 for (int i=0; i<N; i++) {
-                    mDrawables[i] = origDr[i].getConstantState().newDrawable();
+                    if (res != null) {
+                        mDrawables[i] = origDr[i].getConstantState().newDrawable(res);
+                    } else {
+                        mDrawables[i] = origDr[i].getConstantState().newDrawable();
+                    }
                     mDrawables[i].setCallback(owner);
                 }
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index a7a8708..ddbbaf1 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -917,6 +917,11 @@
         }
         
         @Override
+        public Drawable newDrawable(Resources res) {
+            return new GradientDrawable(this);
+        }
+        
+        @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 6047726..4fa9d44 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -49,7 +49,7 @@
     private boolean mMutated;
 
     /*package*/ InsetDrawable() {
-        this(null);
+        this(null, null);
     }
 
     public InsetDrawable(Drawable drawable, int inset) {
@@ -58,7 +58,7 @@
 
     public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
                          int insetRight, int insetBottom) {
-        this(null);
+        this(null, null);
         
         mInsetState.mDrawable = drawable;
         mInsetState.mInsetLeft = insetLeft;
@@ -263,9 +263,13 @@
         boolean mCheckedConstantState;
         boolean mCanConstantState;
 
-        InsetState(InsetState orig, InsetDrawable owner) {
+        InsetState(InsetState orig, InsetDrawable owner, Resources res) {
             if (orig != null) {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mInsetLeft = orig.mInsetLeft;
                 mInsetTop = orig.mInsetTop;
@@ -277,7 +281,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new InsetDrawable(this);
+            return new InsetDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new InsetDrawable(this, res);
         }
         
         @Override
@@ -295,8 +304,8 @@
         }
     }
 
-    private InsetDrawable(InsetState state) {
-        mInsetState = new InsetState(state, this);
+    private InsetDrawable(InsetState state, Resources res) {
+        mInsetState = new InsetState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index c777205..389fd40 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -70,7 +70,7 @@
      * @param state The constant drawable state.
      */
     LayerDrawable(Drawable[] layers, LayerState state) {
-        this(state);
+        this(state, null);
         int length = layers.length;
         ChildDrawable[] r = new ChildDrawable[length];
 
@@ -87,19 +87,19 @@
     }
     
     LayerDrawable() {
-        this((LayerState) null);
+        this((LayerState) null, null);
     }
 
-    LayerDrawable(LayerState state) {
-        LayerState as = createConstantState(state);
+    LayerDrawable(LayerState state, Resources res) {
+        LayerState as = createConstantState(state, res);
         mLayerState = as;
         if (as.mNum > 0) {
             ensurePadding();
         }
     }
 
-    LayerState createConstantState(LayerState state) {
-        return new LayerState(state, this);
+    LayerState createConstantState(LayerState state, Resources res) {
+        return new LayerState(state, this, res);
     }
 
     @Override
@@ -563,7 +563,7 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
-        LayerState(LayerState orig, LayerDrawable owner) {
+        LayerState(LayerState orig, LayerDrawable owner, Resources res) {
             if (orig != null) {
                 final ChildDrawable[] origChildDrawable = orig.mChildren;
                 final int N = orig.mNum;
@@ -577,7 +577,11 @@
                 for (int i = 0; i < N; i++) {
                     final ChildDrawable r = mChildren[i] = new ChildDrawable();
                     final ChildDrawable or = origChildDrawable[i];
-                    r.mDrawable = or.mDrawable.getConstantState().newDrawable();
+                    if (res != null) {
+                        r.mDrawable = or.mDrawable.getConstantState().newDrawable(res);
+                    } else {
+                        r.mDrawable = or.mDrawable.getConstantState().newDrawable();
+                    }
                     r.mDrawable.setCallback(owner);
                     r.mInsetL = or.mInsetL;
                     r.mInsetT = or.mInsetT;
@@ -599,7 +603,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new LayerDrawable(this);
+            return new LayerDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new LayerDrawable(this, res);
         }
         
         @Override
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 7ae649f..ae8f224 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -57,7 +57,7 @@
     private boolean mMutated;
 
     public LevelListDrawable() {
-        this(null);
+        this(null, null);
     }
 
     public void addLevel(int low, int high, Drawable drawable) {
@@ -154,8 +154,8 @@
         private int[] mLows;
         private int[] mHighs;
 
-        LevelListState(LevelListState orig, LevelListDrawable owner) {
-            super(orig, owner);
+        LevelListState(LevelListState orig, LevelListDrawable owner, Resources res) {
+            super(orig, owner, res);
 
             if (orig != null) {
                 mLows = orig.mLows;
@@ -186,7 +186,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new LevelListDrawable(this);
+            return new LevelListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new LevelListDrawable(this, res);
         }
 
         @Override
@@ -201,8 +206,8 @@
         }
     }
 
-    private LevelListDrawable(LevelListState state) {
-        LevelListState as = new LevelListState(state, this);
+    private LevelListDrawable(LevelListState state, Resources res) {
+        LevelListState as = new LevelListState(state, this, res);
         mLevelListState = as;
         setConstantState(as);
         onLevelChange(getLevel());
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 997efb8..803e7b1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -61,7 +61,7 @@
      */
     @Deprecated
     public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
-        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
+        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
     }
     
     /**
@@ -70,11 +70,8 @@
      */
     public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
             Rect padding, String srcName) {
-        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mNinePatchState.mTargetDensity = mTargetDensity;
-        }
+        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
+        mNinePatchState.mTargetDensity = mTargetDensity;
     }
     
     /**
@@ -84,7 +81,7 @@
      */
     @Deprecated
     public NinePatchDrawable(NinePatch patch) {
-        this(new NinePatchState(patch, null));
+        this(new NinePatchState(patch, null), null);
     }
 
     /**
@@ -92,18 +89,16 @@
      * based on the display metrics of the resources.
      */
     public NinePatchDrawable(Resources res, NinePatch patch) {
-        this(new NinePatchState(patch, null));
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mNinePatchState.mTargetDensity = mTargetDensity;
-        }
+        this(new NinePatchState(patch, null), res);
+        mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
-    private void setNinePatchState(NinePatchState state) {
+    private void setNinePatchState(NinePatchState state, Resources res) {
         mNinePatchState = state;
         mNinePatch = state.mNinePatch;
         mPadding = state.mPadding;
-        mTargetDensity = state.mTargetDensity;
+        mTargetDensity = res != null ? res.getDisplayMetrics().densityDpi
+                : state.mTargetDensity;
         if (DEFAULT_DITHER != state.mDither) {
             // avoid calling the setter unless we need to, since it does a
             // lazy allocation of a paint
@@ -258,7 +253,8 @@
         }
 
         setNinePatchState(new NinePatchState(
-                new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), padding, dither));
+                new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
+                padding, dither), r);
         mNinePatchState.mTargetDensity = mTargetDensity;
 
         a.recycle();
@@ -357,7 +353,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new NinePatchDrawable(this);
+            return new NinePatchDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new NinePatchDrawable(this, res);
         }
         
         @Override
@@ -366,8 +367,7 @@
         }
     }
 
-    private NinePatchDrawable(NinePatchState state) {
-        setNinePatchState(state);
+    private NinePatchDrawable(NinePatchState state, Resources res) {
+        setNinePatchState(state, res);
     }
 }
-
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index cb16cb7..c4a7822 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -54,7 +54,7 @@
      * <p>Create a new rotating drawable with an empty state.</p>
      */
     public RotateDrawable() {
-        this(null);
+        this(null, null);
     }
 
     /**
@@ -64,8 +64,8 @@
      *
      * @param rotateState the state for this drawable
      */
-    private RotateDrawable(RotateState rotateState) {
-        mState = new RotateState(rotateState, this);
+    private RotateDrawable(RotateState rotateState, Resources res) {
+        mState = new RotateState(rotateState, this, res);
     }
 
     public void draw(Canvas canvas) {
@@ -291,9 +291,13 @@
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;        
 
-        public RotateState(RotateState source, RotateDrawable owner) {
+        public RotateState(RotateState source, RotateDrawable owner, Resources res) {
             if (source != null) {
-                mDrawable = source.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mPivotXRel = source.mPivotXRel;
                 mPivotX = source.mPivotX;
@@ -307,7 +311,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new RotateDrawable(this);
+            return new RotateDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new RotateDrawable(this, res);
         }
         
         @Override
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 7125ab1..275e36f 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -47,11 +47,11 @@
     private final Rect mTmpRect = new Rect();
 
     ScaleDrawable() {
-        this(null);
+        this(null, null);
     }
 
     public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
-        this(null);
+        this(null, null);
 
         mScaleState.mDrawable = drawable;
         mScaleState.mGravity = gravity;
@@ -260,9 +260,13 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
-        ScaleState(ScaleState orig, ScaleDrawable owner) {
+        ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
             if (orig != null) {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mScaleWidth = orig.mScaleWidth;
                 mScaleHeight = orig.mScaleHeight;
@@ -273,7 +277,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new ScaleDrawable(this);
+            return new ScaleDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new ScaleDrawable(this, res);
         }
 
         @Override
@@ -291,8 +300,8 @@
         }
     }
 
-    private ScaleDrawable(ScaleState state) {
-        mScaleState = new ScaleState(state, this);
+    private ScaleDrawable(ScaleState state, Resources res) {
+        mScaleState = new ScaleState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 6677a35..c699a82 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -396,6 +396,11 @@
         }
         
         @Override
+        public Drawable newDrawable(Resources res) {
+            return new ShapeDrawable(this);
+        }
+        
+        @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 59cb226..b1d588e 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -65,7 +65,7 @@
     private boolean mMutated;
 
     public StateListDrawable() {
-        this(null);
+        this(null, null);
     }
 
     /**
@@ -248,8 +248,8 @@
     static final class StateListState extends DrawableContainerState {
         private int[][] mStateSets;
 
-        StateListState(StateListState orig, StateListDrawable owner) {
-            super(orig, owner);
+        StateListState(StateListState orig, StateListDrawable owner, Resources res) {
+            super(orig, owner, res);
 
             if (orig != null) {
                 mStateSets = orig.mStateSets;
@@ -277,7 +277,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new StateListDrawable(this);
+            return new StateListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new StateListDrawable(this, res);
         }
 
         @Override
@@ -289,8 +294,8 @@
         }
     }
 
-    private StateListDrawable(StateListState state) {
-        StateListState as = new StateListState(state, this);
+    private StateListDrawable(StateListState state, Resources res) {
+        StateListState as = new StateListState(state, this, res);
         mStateListState = as;
         setConstantState(as);
         onStateChange(getState());
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 358f889..97b45d8 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.os.SystemClock;
 
@@ -72,7 +73,7 @@
      * 2 layers are required for this drawable to work properly.
      */
     public TransitionDrawable(Drawable[] layers) {
-        this(new TransitionState(null, null), layers);
+        this(new TransitionState(null, null, null), layers);
     }
 
     /**
@@ -82,11 +83,11 @@
      * @see #TransitionDrawable(Drawable[])
      */
     TransitionDrawable() {
-        this(new TransitionState(null, null));
+        this(new TransitionState(null, null, null), (Resources)null);
     }
 
-    private TransitionDrawable(TransitionState state) {
-        super(state);
+    private TransitionDrawable(TransitionState state, Resources res) {
+        super(state, res);
     }
 
     private TransitionDrawable(TransitionState state, Drawable[] layers) {
@@ -94,8 +95,8 @@
     }
 
     @Override
-    LayerState createConstantState(LayerState state) {
-        return new TransitionState((TransitionState) state, this);
+    LayerState createConstantState(LayerState state, Resources res) {
+        return new TransitionState((TransitionState) state, this, res);
     }
     
     /**
@@ -229,13 +230,19 @@
     }
 
     static class TransitionState extends LayerState {
-        TransitionState(TransitionState orig, TransitionDrawable owner) {
-            super(orig, owner);
+        TransitionState(TransitionState orig, TransitionDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
         }
 
         @Override
         public Drawable newDrawable() {
-            return new TransitionDrawable(this);
+            return new TransitionDrawable(this, (Resources)null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new TransitionDrawable(this, res);
         }
 
         @Override
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 6181f55..8b0f154 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -228,6 +228,8 @@
     friend struct Condition;
     friend struct DequeueCondition;
     friend struct LockCondition;
+    
+    int32_t computeTail() const;
 
     struct QueueUpdate : public UpdateBase {
         inline QueueUpdate(SharedBufferBase* sbb);
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index ae6e255..9ceb8fd 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -143,6 +143,9 @@
             // autoFocus - status returned from callback
             status_t    autoFocus();
 
+            // cancel auto focus
+            status_t    cancelAutoFocus();
+
             // take a picture - picture returned from callback
             status_t    takePicture();
 
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 535f70e..5fbb7d8 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -161,6 +161,14 @@
     virtual status_t    autoFocus() = 0;
 
     /**
+     * Cancels auto-focus function. If the auto-focus is still in progress,
+     * this function will cancel it. Whether the auto-focus is in progress
+     * or not, this function will return the focus position to the default.
+     * If the camera does not support auto-focus, this is a no-op.
+     */
+    virtual status_t    cancelAutoFocus() = 0;
+
+    /**
      * Take a picture.
      */
     virtual status_t    takePicture() = 0;
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
index 1df7914..7595e36 100644
--- a/include/ui/ICamera.h
+++ b/include/ui/ICamera.h
@@ -76,6 +76,9 @@
     // auto focus
     virtual status_t        autoFocus() = 0;
 
+    // cancel auto focus
+    virtual status_t        cancelAutoFocus() = 0;
+
     // take a picture
     virtual status_t        takePicture() = 0;
 
diff --git a/include/utils/threads.h b/include/utils/threads.h
index f5304f7..0fc533f 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -90,11 +90,6 @@
     ANDROID_TGROUP_MAX              = ANDROID_TGROUP_FG_BOOST,
 };
 
-typedef enum {
-    SP_BACKGROUND = 0,
-    SP_FOREGROUND = 1,
-} SchedPolicy;
-
 // Create and run a new thread.
 extern int androidCreateThread(android_thread_func_t, void *);
 
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 790a655..4f7500f 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -677,8 +677,8 @@
     }
 }
 
-void AudioFlinger::audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2) {
-    Mutex::Autolock _l(mLock);
+// audioConfigChanged_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2) {
     int ioHandle = 0;
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
@@ -700,7 +700,7 @@
         size_t size = mNotificationClients.size();
         for (size_t i = 0; i < size; i++) {
             sp<IBinder> binder = mNotificationClients.itemAt(i);
-            LOGV("audioConfigChanged() Notifying change to client %p", binder.get());
+            LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get());
             sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
             client->ioConfigChanged(event, ioHandle, param2);
         }
@@ -803,8 +803,8 @@
         LOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
         ConfigEvent *configEvent = mConfigEvents[0];
         mConfigEvents.removeAt(0);
-        // release mLock because audioConfigChanged() will call
-        // Audioflinger::audioConfigChanged() which locks AudioFlinger mLock thus creating
+        // release mLock because audioConfigChanged() will lock AudioFlinger mLock
+        // before calling Audioflinger::audioConfigChanged_l() thus creating
         // potential cross deadlock between AudioFlinger::mLock and mLock
         mLock.unlock();
         audioConfigChanged(configEvent->mEvent, configEvent->mParam);
@@ -1118,7 +1118,8 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged(event, this, param2);
+    Mutex::Autolock _l(mAudioFlinger->mLock);
+    mAudioFlinger->audioConfigChanged_l(event, this, param2);
 }
 
 void AudioFlinger::PlaybackThread::readOutputParameters()
@@ -1239,7 +1240,7 @@
                 // active tracks were late. Sleep a little bit to give
                 // them another chance. If we're too late, write 0s to audio
                 // hardware to avoid underrun.
-                if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                if (mBytesWritten == 0 || sleepTime < kMaxBufferRecoveryInUsecs) {
                     usleep(kBufferRecoveryInUsecs);
                 } else {
                     memset (curBuf, 0, mixBufferSize);
@@ -1272,8 +1273,6 @@
     if (!mStandby) {
         mOutput->standby();
     }
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
 
     LOGV("MixerThread %p exiting", this);
     return false;
@@ -1741,7 +1740,8 @@
                 standbyTime = systemTime() + kStandbyTimeInNsecs;
             } else {
                 sleepTime += kBufferRecoveryInUsecs;
-                if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                if (mBytesWritten == 0 || !AudioSystem::isLinearPCM(mFormat) ||
+                    sleepTime < kMaxBufferRecoveryInUsecs) {
                     usleep(kBufferRecoveryInUsecs);
                 } else {
                     memset (mMixBuffer, 0, mFrameCount * mFrameSize);
@@ -1771,8 +1771,6 @@
     if (!mStandby) {
         mOutput->standby();
     }
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
 
     LOGV("DirectOutputThread %p exiting", this);
     return false;
@@ -1964,9 +1962,6 @@
         }
     }
 
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
-
     return false;
 }
 
@@ -3046,9 +3041,6 @@
     }
     mActiveTrack.clear();
 
-    sendConfigEvent(AudioSystem::INPUT_CLOSED);
-    processConfigEvents();
-
     LOGV("RecordThread %p exiting", this);
     return false;
 }
@@ -3233,7 +3225,8 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged(event, this, param2);
+    Mutex::Autolock _l(mAudioFlinger->mLock);
+    mAudioFlinger->audioConfigChanged_l(event, this, param2);
 }
 
 void AudioFlinger::RecordThread::readInputParameters()
@@ -3378,6 +3371,8 @@
                 }
             }
         }
+        void *param2 = 0;
+        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, thread, param2);
         mPlaybackThreads.removeItem(output);
     }
     thread->exit();
@@ -3497,6 +3492,8 @@
         }
 
         LOGV("closeInput() %d", input);
+        void *param2 = 0;
+        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, thread, param2);
         mRecordThreads.removeItem(input);
     }
     thread->exit();
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 65c148e..7a6641f 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -616,7 +616,7 @@
               MixerThread *checkMixerThread_l(int output) const;
               RecordThread *checkRecordThread_l(int input) const;
               float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
-              void audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2);
+              void audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2);
 
     friend class AudioBuffer;
 
diff --git a/libs/surfaceflinger/Buffer.cpp b/libs/surfaceflinger/Buffer.cpp
index 4a7c55e..65650aa 100644
--- a/libs/surfaceflinger/Buffer.cpp
+++ b/libs/surfaceflinger/Buffer.cpp
@@ -106,6 +106,9 @@
         // the requested flags should be honored.
         usage = reqUsage | BufferAllocator::USAGE_HW_TEXTURE;
     }
+    
+    if (format == PIXEL_FORMAT_RGBX_8888)
+        format = PIXEL_FORMAT_RGBA_8888;
 
     err = allocator.alloc(w, h, format, usage, &handle, &stride);
     if (err == NO_ERROR) {
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 6275910..1e7f1e6 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -176,6 +176,9 @@
                     // this failed, for instance, because we don't support
                     // NPOT.
                     // FIXME: do something!
+                    LOGD("layer=%p, glEGLImageTargetTexture2DOES(%d) "
+                         "failed err=0x%04x",
+                         this, mTextures[index].image, error);
                     mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
                 } else {
                     // Everything went okay!
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 1f22488..e08861d 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -590,7 +590,8 @@
             glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_RGBA, texture_w, texture_h, 0,
                     GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
-        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888 || 
+                   t.format == GGL_PIXEL_FORMAT_RGBX_8888) {
             glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_RGBA, texture_w, texture_h, 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, data);
@@ -620,7 +621,8 @@
                     0, bounds.top, t.width, bounds.height(),
                     GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
                     t.data + bounds.top*t.stride*2);
-        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888 ||
+                   t.format == GGL_PIXEL_FORMAT_RGBX_8888) {
             glTexSubImage2D(GL_TEXTURE_2D, 0,
                     0, bounds.top, t.width, bounds.height(),
                     GL_RGBA, GL_UNSIGNED_BYTE,
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 8685f99..a352431 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1524,13 +1524,24 @@
                 result.append( l->lcblk->dump("      ") );
                 sp<const Buffer> buf0(l->getBuffer(0));
                 sp<const Buffer> buf1(l->getBuffer(1));
+                uint32_t w0=0, h0=0, s0=0;
+                uint32_t w1=0, h1=0, s1=0;
+                if (buf0 != 0) {
+                    w0 = buf0->getWidth();
+                    h0 = buf0->getHeight();
+                    s0 = buf0->getStride();
+                }
+                if (buf1 != 0) {
+                    w1 = buf1->getWidth();
+                    h1 = buf1->getHeight();
+                    s1 = buf1->getStride();
+                }
                 snprintf(buffer, SIZE,
                         "      "
                         "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
                         " freezeLock=%p\n",
                         l->pixelFormat(),
-                        buf0->getWidth(), buf0->getHeight(), buf0->getStride(),
-                        buf1->getWidth(), buf1->getHeight(), buf1->getStride(),
+                        w0, h0, s0, w1, h1, s1,
                         l->getFreezeLock().get());
                 result.append(buffer);
                 buffer[0] = 0;
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 12a7725..0c6d340 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -242,6 +242,14 @@
     return c->autoFocus();
 }
 
+status_t Camera::cancelAutoFocus()
+{
+    LOGV("cancelAutoFocus");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->cancelAutoFocus();
+}
+
 // take a picture
 status_t Camera::takePicture()
 {
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index 805c2ca..fd7e084 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -32,6 +32,7 @@
     START_PREVIEW,
     STOP_PREVIEW,
     AUTO_FOCUS,
+    CANCEL_AUTO_FOCUS,
     TAKE_PICTURE,
     SET_PARAMETERS,
     GET_PARAMETERS,
@@ -162,6 +163,17 @@
         return ret;
     }
 
+    // cancel focus
+    status_t cancelAutoFocus()
+    {
+        LOGV("cancelAutoFocus");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(CANCEL_AUTO_FOCUS, data, &reply);
+        status_t ret = reply.readInt32();
+        return ret;
+    }
+
     // take a picture - returns an IMemory (ref-counted mmap)
     status_t takePicture()
     {
@@ -294,6 +306,12 @@
             reply->writeInt32(autoFocus());
             return NO_ERROR;
         } break;
+        case CANCEL_AUTO_FOCUS: {
+            LOGV("CANCEL_AUTO_FOCUS");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(cancelAutoFocus());
+            return NO_ERROR;
+        } break;
         case TAKE_PICTURE: {
             LOGV("TAKE_PICTURE");
             CHECK_INTERFACE(ICamera, data, reply);
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
index 436d793..7789a3f 100644
--- a/libs/ui/SharedBufferStack.cpp
+++ b/libs/ui/SharedBufferStack.cpp
@@ -246,19 +246,26 @@
         int surface, int num)
     : SharedBufferBase(sharedClient, surface, num), tail(0)
 {
+    tail = computeTail();
+}
+
+int32_t SharedBufferClient::computeTail() const
+{
     SharedBufferStack& stack( *mSharedStack );
-    int32_t avail;
-    int32_t head;
     // we need to make sure we read available and head coherently,
     // w.r.t RetireUpdate.
+    int32_t newTail;
+    int32_t avail;
+    int32_t head;
     do {
         avail = stack.available;
         head = stack.head;
     } while (stack.available != avail);
-    tail = head - avail + 1;
-    if (tail < 0) {
-        tail += num;
+    newTail = head - avail + 1;
+    if (newTail < 0) {
+        newTail += mNumBuffers;
     }
+    return newTail;
 }
 
 ssize_t SharedBufferClient::dequeue()
@@ -296,6 +303,9 @@
 {
     UndoDequeueUpdate update(this);
     status_t err = updateCondition( update );
+    if (err == NO_ERROR) {
+        tail = computeTail();
+    }
     return err;
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d905619..22c2f39 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1266,6 +1266,8 @@
 
         CHECK_EQ(info->mOwnedByComponent, false);
 
+        CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
+
         status_t err =
             mOMX->free_buffer(mNode, portIndex, info->mBuffer);
 
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index 8710c64..504fe35 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -169,10 +169,10 @@
                 mHasBody = true;
             }
 
-            if (requestHeader.mConnectionID != null) {
+            if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
                 mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
             } else {
-                mListener.setConnectionId(0);
+                mListener.setConnectionId(1);
             }
 
             if (requestHeader.mAuthResp != null) {
@@ -438,7 +438,7 @@
                     if (body != null) {
                         mHasBody = true;
                     }
-                    if (requestHeader.mConnectionID != null) {
+                    if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
                         mListener.setConnectionId(ObexHelper
                                 .convertToLong(requestHeader.mConnectionID));
                     } else {
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index 675272d..aca90bb 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -283,10 +283,10 @@
 
                 ObexHelper.updateHeaderSet(request, headers);
 
-                if (request.mConnectionID != null) {
+                if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
                     mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
                 } else {
-                    mListener.setConnectionId(-1);
+                    mListener.setConnectionId(1);
                 }
                 // the Auth chan is initiated by the server, client sent back the authResp .
                 if (request.mAuthResp != null) {
@@ -405,7 +405,7 @@
                 ObexHelper.updateHeaderSet(request, headers);
             }
 
-            if (request.mConnectionID != null) {
+            if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
                 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
             } else {
                 mListener.setConnectionId(1);
@@ -527,7 +527,7 @@
                 ObexHelper.updateHeaderSet(request, headers);
             }
 
-            if (request.mConnectionID != null) {
+            if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
                 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
             } else {
                 mListener.setConnectionId(1);
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 6b20445..d5f1c61 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -27,6 +27,7 @@
     <bool name="def_accelerometer_rotation">true</bool>
     <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
     <integer name="def_screen_brightness">102</integer>
+    <bool name="def_screen_brightness_automatic_mode">false</bool>
     <fraction name="def_window_animation_scale">100%</fraction>
     <fraction name="def_window_transition_scale">0%</fraction>
     
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 2524a30..f99eb58 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -71,7 +71,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 39;
+    private static final int DATABASE_VERSION = 40;
 
     private Context mContext;
 
@@ -465,6 +465,22 @@
             upgradeVersion = 39;
         }
 
+        if (upgradeVersion == 39) {
+            db.beginTransaction();
+            try {
+                String value =
+                        mContext.getResources().getBoolean(
+                        R.bool.def_screen_brightness_automatic_mode) ? "1" : "0";
+                db.execSQL("INSERT OR IGNORE INTO system(name,value) values('" +
+                        Settings.System.SCREEN_BRIGHTNESS_MODE + "','" + value + "');");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+
+            upgradeVersion = 40;
+        }
+
         if (upgradeVersion != currentVersion) {
             Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
                     + ", must wipe the settings provider");
@@ -701,6 +717,9 @@
         loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
                 R.integer.def_screen_brightness);
 
+        loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,
+                R.bool.def_screen_brightness_automatic_mode);
+
         loadDefaultAnimationSettings(stmt);
 
         loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 7385359..30c25e0 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemClock;
 import android.os.UEventObserver;
 import android.util.Log;
 
@@ -41,8 +42,11 @@
 
     private final Context mContext;
 
-    public DockObserver(Context context) {
+    private PowerManagerService mPowerManager;
+
+    public DockObserver(Context context, PowerManagerService pm) {
         mContext = context;
+        mPowerManager = pm;
         init();  // set initial status
         startObserving(DOCK_UEVENT_MATCH);
     }
@@ -103,6 +107,7 @@
             synchronized (this) {
                 Log.d(TAG, "Broadcasting dock state " + mDockState);
                 // Pack up the values and broadcast them to everyone
+                mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
                 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
                 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
                 mContext.sendStickyBroadcast(intent);
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index 6ac72e0..01daae3 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -59,6 +59,8 @@
     private boolean mAttentionLightOn;
     private boolean mPulsing;
 
+    private boolean mAutoBrightnessAvailable;
+
     private class Vibration implements IBinder.DeathRecipient {
         private final IBinder mToken;
         private final long    mTimeout;
@@ -129,6 +131,9 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         context.registerReceiver(mIntentReceiver, filter);
+
+        mAutoBrightnessAvailable = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_automatic_brightness_available);
     }
 
     protected void finalize() throws Throwable {
@@ -302,6 +307,20 @@
         setLight_native(mNativePointer, light, color, mode, onMS, offMS);
     }
 
+    public void setAutoBrightness(boolean on) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires HARDWARE_TEST permission");
+        }
+        setAutoBrightness_UNCHECKED(on);
+    }
+
+    void setAutoBrightness_UNCHECKED(boolean on) {
+        if (mAutoBrightnessAvailable) {
+            setAutoBrightness_native(mNativePointer, on);
+        }
+    }
+
     public void setAttentionLight(boolean on) {
         // Not worthy of a permission.  We shouldn't have a flashlight permission.
         synchronized (this) {
@@ -502,6 +521,7 @@
     private static native int init_native();
     private static native void finalize_native(int ptr);
 
+    private static native void setAutoBrightness_native(int ptr, boolean automatic);
     private static native void setLight_native(int ptr, int light, int color, int mode,
             int onMS, int offMS);
 
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 244e136..d9f4c9c 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -981,6 +981,29 @@
         }
     }
 
+    /**
+     * Return true if the queue has an up event pending that corresponds
+     * to the same key as the given key event.
+     */
+    boolean hasKeyUpEvent(KeyEvent origEvent) {
+        synchronized (mFirst) {
+            final int keyCode = origEvent.getKeyCode();
+            QueuedEvent cur = mLast.prev;
+            while (cur.prev != null) {
+                if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
+                    KeyEvent ke = (KeyEvent)cur.event;
+                    if (ke.getAction() == KeyEvent.ACTION_UP
+                            && ke.getKeyCode() == keyCode) {
+                        return true;
+                    }
+                }
+                cur = cur.prev;
+            }
+        }
+        
+        return false;
+    }
+    
     void recycleEvent(QueuedEvent ev) {
         synchronized (mFirst) {
             //Log.i(TAG, "Recycle event: " + ev);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index ba65f01..2951384 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -52,6 +52,7 @@
 import android.view.WindowManagerPolicy;
 import static android.provider.Settings.System.DIM_SCREEN;
 import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
+import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
 import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN;
 
@@ -87,6 +88,9 @@
     private static final int LONG_KEYLIGHT_DELAY = 6000;        // t+6 sec
     private static final int LONG_DIM_TIME = 7000;              // t+N-5 sec
 
+    // trigger proximity if distance is less than 5 cm
+    private static final float PROXIMITY_THRESHOLD = 5.0f;
+
     // Cached Gservices settings; see updateGservicesValues()
     private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
 
@@ -442,7 +446,11 @@
 
         // turn everything on
         setPowerState(ALL_BRIGHT);
-        
+
+        // set auto brightness mode to user setting
+        boolean brightnessMode = Settings.System.getInt(resolver, SCREEN_BRIGHTNESS_MODE, 1) != 0;
+        mHardware.setAutoBrightness_UNCHECKED(brightnessMode);
+
         synchronized (mHandlerThread) {
             mInitComplete = true;
             mHandlerThread.notifyAll();
@@ -2079,18 +2087,19 @@
     public void onSensorChanged(SensorEvent event) {
         long milliseconds = event.timestamp / 1000000;
         synchronized (mLocks) {
-            if (event.values[0] == 0.0) {
+            float distance = event.values[0];
+            if (distance >= 0.0 && distance < PROXIMITY_THRESHOLD) {
                 if (mSpew) {
-                    Log.d(TAG, "onSensorChanged: proximity active");
+                    Log.d(TAG, "onSensorChanged: proximity active, distance: " + distance);
                 }
                 goToSleepLocked(milliseconds);
                 mProximitySensorActive = true;
             } else {
-                // proximity sensor negative events user activity.
+                // proximity sensor negative events trigger as user activity.
                 // temporarily set mUserActivityAllowed to true so this will work
                 // even when the keyguard is on.
                 if (mSpew) {
-                    Log.d(TAG, "onSensorChanged: proximity inactive");
+                    Log.d(TAG, "onSensorChanged: proximity inactive, distance: " + distance);
                 }
                 mProximitySensorActive = false;
                 boolean savedActivityAllowed = mUserActivityAllowed;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7c2a7ac..b3b50e5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -330,7 +330,7 @@
             try {
                 Log.i(TAG, "Dock Observer");
                 // Listen for dock station changes
-                dock = new DockObserver(context);
+                dock = new DockObserver(context, power);
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting DockObserver", e);
             }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index b0e4038..8e85a6a 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -99,6 +99,7 @@
 import android.view.Surface;
 import android.view.SurfaceSession;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
@@ -151,9 +152,6 @@
 
     static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
 
-    /** How long to wait for first key repeat, in milliseconds */
-    static final int KEY_REPEAT_FIRST_DELAY = 750;
-
     /** How long to wait for subsequent key repeats, in milliseconds */
     static final int KEY_REPEAT_DELAY = 50;
 
@@ -418,6 +416,17 @@
     int mWallpaperAnimLayerAdjustment;
     float mLastWallpaperX;
     float mLastWallpaperY;
+    // Lock for waiting for the wallpaper.
+    final Object mWaitingOnWallpaperLock = new Object();
+    // This is set when we are waiting for a wallpaper to tell us it is done
+    // changing its scroll position.
+    WindowState mWaitingOnWallpaper;
+    // The last time we had a timeout when waiting for a wallpaper.
+    long mLastWallpaperTimeoutTime;
+    // We give a wallpaper up to 150ms to finish scrolling.
+    static final long WALLPAPER_TIMEOUT = 150;
+    // Time we wait after a timeout before trying to wait again.
+    static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
     
     AppWindowToken mFocusedApp = null;
 
@@ -1427,7 +1436,7 @@
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 
                 if (visible) {
-                    updateWallpaperOffsetLocked(wallpaper, dw, dh);                        
+                    updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
                 
                 // First, make sure the client has the current visibility
@@ -1498,7 +1507,8 @@
         }
     }
 
-    boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh) {
+    boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh,
+            boolean sync) {
         boolean changed = false;
         boolean rawChanged = false;
         if (mLastWallpaperX >= 0) {
@@ -1536,8 +1546,37 @@
                 if (DEBUG_WALLPAPER) Log.v(TAG, "Report new wp offset "
                         + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
                         + " y=" + wallpaperWin.mWallpaperY);
+                if (sync) {
+                    synchronized (mWaitingOnWallpaperLock) {
+                        mWaitingOnWallpaper = wallpaperWin;
+                    }
+                }
                 wallpaperWin.mClient.dispatchWallpaperOffsets(
-                        wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
+                        wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, sync);
+                if (sync) {
+                    synchronized (mWaitingOnWallpaperLock) {
+                        if (mWaitingOnWallpaper != null) {
+                            long start = SystemClock.uptimeMillis();
+                            if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
+                                    < start) {
+                                try {
+                                    if (DEBUG_WALLPAPER) Log.v(TAG,
+                                            "Waiting for offset complete...");
+                                    mWaitingOnWallpaperLock.wait(WALLPAPER_TIMEOUT);
+                                } catch (InterruptedException e) {
+                                }
+                                if (DEBUG_WALLPAPER) Log.v(TAG, "Offset complete!");
+                                if ((start+WALLPAPER_TIMEOUT)
+                                        < SystemClock.uptimeMillis()) {
+                                    Log.i(TAG, "Timeout waiting for wallpaper to offset: "
+                                            + wallpaperWin);
+                                    mLastWallpaperTimeoutTime = start;
+                                }
+                            }
+                            mWaitingOnWallpaper = null;
+                        }
+                    }
+                }
             } catch (RemoteException e) {
             }
         }
@@ -1545,7 +1584,17 @@
         return changed;
     }
     
-    boolean updateWallpaperOffsetLocked() {
+    void wallpaperOffsetsComplete(IBinder window) {
+        synchronized (mWaitingOnWallpaperLock) {
+            if (mWaitingOnWallpaper != null &&
+                    mWaitingOnWallpaper.mClient.asBinder() == window) {
+                mWaitingOnWallpaper = null;
+                mWaitingOnWallpaperLock.notifyAll();
+            }
+        }
+    }
+    
+    boolean updateWallpaperOffsetLocked(boolean sync) {
         final int dw = mDisplay.getWidth();
         final int dh = mDisplay.getHeight();
         
@@ -1563,9 +1612,11 @@
                 while (curWallpaperIndex > 0) {
                     curWallpaperIndex--;
                     WindowState wallpaper = token.windows.get(curWallpaperIndex);
-                    if (updateWallpaperOffsetLocked(wallpaper, dw, dh)) {
+                    if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
                         wallpaper.computeShownFrameLocked();
                         changed = true;
+                        // We only want to be synchronous with one wallpaper.
+                        sync = false;
                     }
                 }
             }
@@ -1595,7 +1646,7 @@
                 curWallpaperIndex--;
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 if (visible) {
-                    updateWallpaperOffsetLocked(wallpaper, dw, dh);                        
+                    updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
                 
                 if (wallpaper.mWallpaperVisible != visible) {
@@ -1782,8 +1833,10 @@
                 imMayMove = false;
             } else {
                 addWindowToListInOrderLocked(win, true);
-                if (attrs.type == TYPE_WALLPAPER ||
-                        (attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+                if (attrs.type == TYPE_WALLPAPER) {
+                    mLastWallpaperTimeoutTime = 0;
+                    adjustWallpaperWindowsLocked();
+                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                     adjustWallpaperWindowsLocked();
                 }
             }
@@ -1992,8 +2045,10 @@
             }
         }
 
-        if (win.mAttrs.type == TYPE_WALLPAPER ||
-                (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+        if (win.mAttrs.type == TYPE_WALLPAPER) {
+            mLastWallpaperTimeoutTime = 0;
+            adjustWallpaperWindowsLocked();
+        } else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
             adjustWallpaperWindowsLocked();
         }
         
@@ -2070,7 +2125,7 @@
             window.mWallpaperY = y;
             
             if (mWallpaperTarget == window) {
-                if (updateWallpaperOffsetLocked()) {
+                if (updateWallpaperOffsetLocked(true)) {
                     performLayoutAndPlaceSurfacesLocked();
                 }
             }
@@ -2258,7 +2313,7 @@
             performLayoutAndPlaceSurfacesLocked();
             if (displayed && win.mIsWallpaper) {
                 updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
-                        mDisplay.getHeight());
+                        mDisplay.getHeight(), false);
             }
             if (win.mAppToken != null) {
                 win.mAppToken.updateReportedVisibilityLocked();
@@ -4843,6 +4898,16 @@
             return INJECT_SUCCEEDED;
         }
 
+        // Okay we have finished waiting for the last event to be processed.
+        // First off, if this is a repeat event, check to see if there is
+        // a corresponding up event in the queue.  If there is, we will
+        // just drop the repeat, because it makes no sense to repeat after
+        // the user has released a key.  (This is especially important for
+        // long presses.)
+        if (event.getRepeatCount() > 0 && mQueue.hasKeyUpEvent(event)) {
+            return INJECT_SUCCEEDED;
+        }
+        
         WindowState focus = (WindowState)focusObj;
 
         if (DEBUG_INPUT) Log.v(
@@ -5961,6 +6026,7 @@
             // Last keydown time for auto-repeating keys
             long lastKeyTime = SystemClock.uptimeMillis();
             long nextKeyTime = lastKeyTime+LONG_WAIT;
+            long downTime = 0;
 
             // How many successive repeats we generated
             int keyRepeatCount = 0;
@@ -6031,15 +6097,17 @@
                                 KeyEvent ke = (KeyEvent)ev.event;
                                 if (ke.isDown()) {
                                     lastKey = ke;
+                                    downTime = curTime;
                                     keyRepeatCount = 0;
                                     lastKeyTime = curTime;
                                     nextKeyTime = lastKeyTime
-                                            + KEY_REPEAT_FIRST_DELAY;
+                                            + ViewConfiguration.getLongPressTimeout();
                                     if (DEBUG_INPUT) Log.v(
                                         TAG, "Received key down: first repeat @ "
                                         + nextKeyTime);
                                 } else {
                                     lastKey = null;
+                                    downTime = 0;
                                     // Arbitrary long timeout.
                                     lastKeyTime = curTime;
                                     nextKeyTime = curTime + LONG_WAIT;
@@ -6087,7 +6155,19 @@
                         if (DEBUG_INPUT) Log.v(
                             TAG, "Key repeat: count=" + keyRepeatCount
                             + ", next @ " + nextKeyTime);
-                        dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
+                        KeyEvent newEvent;
+                        if (downTime != 0 && (downTime
+                                + ViewConfiguration.getLongPressTimeout())
+                                <= curTime) {
+                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
+                                    curTime, keyRepeatCount,
+                                    lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
+                            downTime = 0;
+                        } else {
+                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
+                                    curTime, keyRepeatCount);
+                        }
+                        dispatchKey(newEvent, 0, 0);
 
                     } else {
                         curTime = SystemClock.uptimeMillis();
@@ -6303,6 +6383,10 @@
             }
         }
         
+        public void wallpaperOffsetsComplete(IBinder window) {
+            WindowManagerService.this.wallpaperOffsetsComplete(window);
+        }
+        
         void windowAddedLocked() {
             if (mSurfaceSession == null) {
                 if (localLOGV) Log.v(
@@ -6698,7 +6782,7 @@
 
             if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
                 updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
-                        mDisplay.getHeight());
+                        mDisplay.getHeight(), false);
             }
             
             if (localLOGV) {
diff --git a/services/jni/com_android_server_HardwareService.cpp b/services/jni/com_android_server_HardwareService.cpp
index 22d4bd8..a17e29f 100644
--- a/services/jni/com_android_server_HardwareService.cpp
+++ b/services/jni/com_android_server_HardwareService.cpp
@@ -100,6 +100,18 @@
     free(devices);
 }
 
+static void setAutoBrightness_native(JNIEnv *env, jobject clazz, int ptr,
+        jboolean automatic)
+{
+    Devices* devices = (Devices*)ptr;
+
+    if (devices->lights[LIGHT_INDEX_BACKLIGHT] == NULL) {
+        return;
+    }
+
+    devices->lights[LIGHT_INDEX_BACKLIGHT]->set_als_mode(automatic ? 0 : 1);
+}
+
 static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
         int light, int colorARGB, int flashMode, int onMS, int offMS)
 {
@@ -134,6 +146,7 @@
 static JNINativeMethod method_table[] = {
     { "init_native", "()I", (void*)init_native },
     { "finalize_native", "(I)V", (void*)finalize_native },
+    { "setAutoBrightness_native", "(IZ)V", (void*)setAutoBrightness_native },
     { "setLight_native", "(IIIIII)V", (void*)setLight_native },
     { "vibratorOn", "(J)V", (void*)vibratorOn },
     { "vibratorOff", "()V", (void*)vibratorOff }
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index ffcfe6f..8b54ca8 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -181,7 +181,7 @@
             return null;
         }
 
-        StringBuilder buf = new StringBuilder("content://im/");
+        StringBuilder buf = new StringBuilder("content://icc/");
         switch (match) {
             case ADN:
                 buf.append("adn/");
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 623d985..386dc3d46 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -299,14 +299,16 @@
 
         // Build up the data stream
         ByteArrayOutputStream output = new ByteArrayOutputStream();
-        for (int i = 0; i < totalSegments-1; i++) {
+        for (int i = 0; i < totalSegments; i++) {
             // reassemble the (WSP-)pdu
-            output.write(pdus[i], 0, pdus[i].length);
+            if (i == segment) {
+                // This one isn't in the DB, so add it
+                output.write(pdu, index, pdu.length - index);
+            } else {
+                output.write(pdus[i], 0, pdus[i].length);
+            }
         }
 
-        // This one isn't in the DB, so add it
-        output.write(pdu, index, pdu.length - index);
-
         byte[] datagram = output.toByteArray();
         // Dispatch the PDU to applications
         switch (destinationPort) {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java
index a504cd3..a9be5bd 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java
@@ -33,7 +33,7 @@
 public class FileObserverTest extends AndroidTestCase {
     private Observer mObserver;
     private File mTestFile;
-    
+
     private static class Observer extends FileObserver {
         public List<Map> events = Lists.newArrayList();
         public int totalEvents = 0;
@@ -56,10 +56,10 @@
             }
         }
     }
-    
+
     @Override
     protected void setUp() throws Exception {
-        mTestFile = File.createTempFile(".file_observer_test", ".txt"); 
+        mTestFile = File.createTempFile(".file_observer_test", ".txt");
     }
 
     @Override
@@ -68,13 +68,13 @@
             mTestFile.delete();
         }
     }
-    
+
     @LargeTest
     public void testRun() throws Exception {
         // make file changes and wait for them
         assertTrue(mTestFile.exists());
         assertNotNull(mTestFile.getParent());
-        
+
         mObserver = new Observer(mTestFile.getParent());
         mObserver.startWatching();
 
@@ -85,10 +85,11 @@
             waitForEvent(); // modify
 
             mTestFile.delete();
+            waitForEvent(); // modify
             waitForEvent(); // delete
 
             mObserver.stopWatching();
-            
+
             // Ensure that we have seen at least 3 events.
             assertTrue(mObserver.totalEvents > 3);
         } finally {
@@ -111,10 +112,41 @@
 
             while (it.hasNext()) {
                 Map map = it.next();
-                Log.i("FileObserverTest", "event: " + map.get("event").toString() + " path: " + map.get("path"));
+                Log.i("FileObserverTest", "event: " + getEventString((Integer)map.get("event")) + " path: " + map.get("path"));
             }
 
             mObserver.events.clear();
         }
     }
+
+    private String getEventString(int event) {
+        switch (event) {
+            case  FileObserver.ACCESS:
+                return "ACCESS";
+            case FileObserver.MODIFY:
+                return "MODIFY";
+            case FileObserver.ATTRIB:
+                return "ATTRIB";
+            case FileObserver.CLOSE_WRITE:
+                return "CLOSE_WRITE";
+            case FileObserver.CLOSE_NOWRITE:
+                return "CLOSE_NOWRITE";
+            case FileObserver.OPEN:
+                return "OPEN";
+            case FileObserver.MOVED_FROM:
+                return "MOVED_FROM";
+            case FileObserver.MOVED_TO:
+                return "MOVED_TO";
+            case FileObserver.CREATE:
+                return "CREATE";
+            case FileObserver.DELETE:
+                return "DELETE";
+            case FileObserver.DELETE_SELF:
+                return "DELETE_SELF";
+            case FileObserver.MOVE_SELF:
+                return "MOVE_SELF";
+            default:
+                return "UNKNOWN";
+        }
+    }
 }
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index c3e6b5b..c3627bb 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -197,7 +197,17 @@
     logging.error("DumpRenderTree crashed, output:\n" + adb_output)
 
     shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
-    crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
+    crashed_test = ""
+    while not crashed_test:
+      (crashed_test, err) = subprocess.Popen(
+          shell_cmd_str, shell=True, stdout=subprocess.PIPE,
+          stderr=subprocess.PIPE).communicate()
+      crashed_test = crashed_test.strip()
+      if not crashed_test:
+        logging.error('Cannot get crashed test name, device offline?')
+        logging.error('stderr: ' + err)
+        logging.error('retrying in 10s...')
+        time.sleep(10)
 
     logging.info(crashed_test + " CRASHED");
     crashed_tests.append(crashed_test);
diff --git a/tests/DumpRenderTree/assets/run_reliability_tests.py b/tests/DumpRenderTree/assets/run_reliability_tests.py
index 23f93df..59ac4a3 100755
--- a/tests/DumpRenderTree/assets/run_reliability_tests.py
+++ b/tests/DumpRenderTree/assets/run_reliability_tests.py
@@ -195,8 +195,18 @@
   while not DumpRenderTreeFinished(adb_cmd):
     logging.error("DumpRenderTree exited before all URLs are visited.")
     shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE
-    crashed_test = subprocess.Popen(shell_cmd_str, shell=True,
-                                    stdout=subprocess.PIPE).communicate()[0]
+    crashed_test = ""
+    while not crashed_test:
+      (crashed_test, err) = subprocess.Popen(
+          shell_cmd_str, shell=True, stdout=subprocess.PIPE,
+          stderr=subprocess.PIPE).communicate()
+      crashed_test = crashed_test.strip()
+      if not crashed_test:
+        logging.error('Cannot get crashed test name, device offline?')
+        logging.error('stderr: ' + err)
+        logging.error('retrying in 10s...')
+        time.sleep(10)
+
     logging.info(crashed_test + " CRASHED")
     crashed_tests.append(crashed_test)
     Bugreport(crashed_test, bugreport_dir, adb_cmd)
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 55fe4ac..0888fd8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -1051,15 +1051,22 @@
             // pass for now.
         }
 
+        @SuppressWarnings("unused")
         public void setInsets(IWindow window, int touchable, Rect contentInsets,
                 Rect visibleInsets) {
             // pass for now.
         }
 
+        @SuppressWarnings("unused")
         public void setWallpaperPosition(IBinder window, float x, float y) {
             // pass for now.
         }
 
+        @SuppressWarnings("unused")
+        public void wallpaperOffsetsComplete(IBinder window) {
+            // pass for now.
+        }
+        
         public IBinder asBinder() {
             // pass for now.
             return null;
@@ -1114,7 +1121,7 @@
         }
 
         @SuppressWarnings("unused")
-        public void dispatchWallpaperOffsets(float x, float y) {
+        public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
             // pass for now.
         }