Merge change 25090 into eclair

* changes:
  Move backlight brightness from HardwareService to PowerManager
diff --git a/api/current.xml b/api/current.xml
index 38490f3..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>
@@ -150079,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"
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/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/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/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/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 2329e21..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;
@@ -1835,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
@@ -2675,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) {
@@ -2771,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
@@ -2838,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;
@@ -3312,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();
@@ -3365,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() ?
@@ -3479,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;
         }
 
@@ -3630,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()) {
@@ -3962,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);
@@ -3980,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
@@ -4039,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) {
@@ -4097,8 +3687,7 @@
                     if (settings.supportZoom()
                             && settings.getBuiltInZoomControls()
                             && !mZoomButtonsController.isVisible()
-                            && (canZoomScrollOut() ||
-                                    mMinZoomScale < mMaxZoomScale)) {
+                            && mMinZoomScale < mMaxZoomScale) {
                         mZoomButtonsController.setVisible(true);
                     }
                 }
@@ -4165,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);
@@ -4193,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);
@@ -4215,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
@@ -4270,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);
@@ -4372,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
@@ -4512,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);
@@ -4750,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;
     }
 
@@ -4802,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();
@@ -4889,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);
     }
 
@@ -5259,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
@@ -5286,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());
                     }
@@ -5745,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);
     }
 
     /**
@@ -5785,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/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/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/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 7749ad34..30c81ab 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -113,6 +113,10 @@
         mRS.nAllocationSubDataFromObject(mID, mType, 0, o);
     }
 
+    public void read(Object o) {
+        mRS.nAllocationSubReadFromObject(mID, mType, 0, o);
+    }
+
     public void subData(int offset, Object o) {
         mRS.nAllocationSubDataFromObject(mID, mType, offset, o);
     }
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 6f5b67e..89db4fa 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -106,6 +106,7 @@
     native void nAllocationRead(int id, int[] d);
     native void nAllocationRead(int id, float[] d);
     native void nAllocationSubDataFromObject(int id, Type t, int offset, Object o);
+    native void nAllocationSubReadFromObject(int id, Type t, int offset, Object o);
 
     native void nTriangleMeshBegin(int vertex, int index);
     native void nTriangleMeshAddVertex_XY (float x, float y);
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index a94ccb1..90b5958 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -253,10 +253,39 @@
     return ((uint8_t *)buffer) + 4;
 }
 
+static void * SF_SaveInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+    LOGE("Save Int");
+    _env->SetIntField(_obj, _field, ((int32_t *)buffer)[0]);
+    return ((uint8_t *)buffer) + 4;
+}
+
+static void * SF_SaveShort(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+    LOGE("Save Short");
+    _env->SetShortField(_obj, _field, ((int16_t *)buffer)[0]);
+    return ((uint8_t *)buffer) + 2;
+}
+
+static void * SF_SaveByte(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+    LOGE("Save Byte");
+    _env->SetByteField(_obj, _field, ((int8_t *)buffer)[0]);
+    return ((uint8_t *)buffer) + 1;
+}
+
+static void * SF_SaveFloat(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+    LOGE("Save Float");
+    _env->SetFloatField(_obj, _field, ((float *)buffer)[0]);
+    return ((uint8_t *)buffer) + 4;
+}
+
 struct TypeFieldCache {
     jfieldID field;
     int bits;
     void * (*ptr)(JNIEnv *, jobject, jfieldID, void *buffer);
+    void * (*readPtr)(JNIEnv *, jobject, jfieldID, void *buffer);
 };
 
 struct TypeCache {
@@ -296,13 +325,23 @@
         switch(fType[ct]) {
         case RS_TYPE_FLOAT:
             tfc[ct].ptr = SF_LoadFloat;
+            tfc[ct].readPtr = SF_SaveFloat;
             break;
         case RS_TYPE_UNSIGNED:
         case RS_TYPE_SIGNED:
             switch(tfc[ct].bits) {
-            case 32:    tfc[ct].ptr = SF_LoadInt;   break;
-            case 16:    tfc[ct].ptr = SF_LoadShort; break;
-            case 8:     tfc[ct].ptr = SF_LoadByte;  break;
+            case 32:
+                tfc[ct].ptr = SF_LoadInt;
+                tfc[ct].readPtr = SF_SaveInt;
+                break;
+            case 16:
+                tfc[ct].ptr = SF_LoadShort;
+                tfc[ct].readPtr = SF_SaveShort;
+                break;
+            case 8:
+                tfc[ct].ptr = SF_LoadByte;
+                tfc[ct].readPtr = SF_SaveByte;
+                break;
             }
             break;
         }
@@ -545,7 +584,30 @@
         buf = tfc->ptr(_env, _o, tfc->field, buf);
     }
     rsAllocation1DSubData(con, (RsAllocation)alloc, offset, 1, bufAlloc, tc->size);
-    const uint32_t * tmp = (const uint32_t *)bufAlloc;
+    free(bufAlloc);
+}
+
+static void
+nAllocationSubReadFromObject(JNIEnv *_env, jobject _this, jint alloc, jobject _type, jint offset, jobject _o)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nAllocationReadFromObject con(%p), alloc(%p)", con, (RsAllocation)alloc);
+
+    assert(offset == 0);
+
+    const TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache);
+
+    void * bufAlloc = malloc(tc->size);
+    void * buf = bufAlloc;
+    rsAllocationRead(con, (RsAllocation)alloc, bufAlloc);
+
+    LOGE("size %i, ", tc->size);
+
+    for (int ct=0; ct < tc->fieldCount; ct++) {
+        const TypeFieldCache *tfc = &tc->fields[ct];
+        LOGE("ct=%i, buf=%p", ct, buf);
+        buf = tfc->readPtr(_env, _o, tfc->field, buf);
+    }
     free(bufAlloc);
 }
 
@@ -1270,6 +1332,7 @@
 {"nAllocationRead",                "(I[I)V",                               (void*)nAllocationRead_i },
 {"nAllocationRead",                "(I[F)V",                               (void*)nAllocationRead_f },
 {"nAllocationSubDataFromObject",   "(ILandroid/renderscript/Type;ILjava/lang/Object;)V",   (void*)nAllocationSubDataFromObject },
+{"nAllocationSubReadFromObject",   "(ILandroid/renderscript/Type;ILjava/lang/Object;)V",   (void*)nAllocationSubReadFromObject },
 
 {"nTriangleMeshBegin",             "(II)V",                                (void*)nTriangleMeshBegin },
 {"nTriangleMeshAddVertex_XY",      "(FF)V",                                (void*)nTriangleMeshAddVertex_XY },
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index d9be007..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()
@@ -1272,8 +1273,6 @@
     if (!mStandby) {
         mOutput->standby();
     }
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
 
     LOGV("MixerThread %p exiting", this);
     return false;
@@ -1772,8 +1771,6 @@
     if (!mStandby) {
         mOutput->standby();
     }
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
 
     LOGV("DirectOutputThread %p exiting", this);
     return false;
@@ -1965,9 +1962,6 @@
         }
     }
 
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
-
     return false;
 }
 
@@ -3047,9 +3041,6 @@
     }
     mActiveTrack.clear();
 
-    sendConfigEvent(AudioSystem::INPUT_CLOSED);
-    processConfigEvents();
-
     LOGV("RecordThread %p exiting", this);
     return false;
 }
@@ -3234,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()
@@ -3379,6 +3371,8 @@
                 }
             }
         }
+        void *param2 = 0;
+        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, thread, param2);
         mPlaybackThreads.removeItem(output);
     }
     thread->exit();
@@ -3498,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/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/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";
+        }
+    }
 }