Merge "Updated text cursor assets" into honeycomb-mr1
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 440cb54..efe2633 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1150,8 +1150,12 @@
      * fail (most commonly returning {@link #ENCRYPTION_STATUS_ACTIVE}).
      *
      * <p>This policy controls encryption of the secure (application data) storage area.  Data
-     * written to other areas (e.g. the directory returned by
-     * {@link android.os.Environment#getExternalStorageDirectory()} may or may not be encrypted.
+     * written to other storage areas may or may not be encrypted, and this policy does not require
+     * or control the encryption of any other storage areas.
+     * There is one exception:  If {@link android.os.Environment#isExternalStorageEmulated()} is
+     * {@code true}, then the directory returned by
+     * {@link android.os.Environment#getExternalStorageDirectory()} must be written to disk
+     * within the encrypted storage area.
      *
      * <p>Important Note:  On some devices, it is possible to encrypt storage without requiring
      * the user to create a device PIN or Password.  In this case, the storage is encrypted, but
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ec5030c..e308c2c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -423,9 +423,16 @@
 
     /**
      * Returns whether the device has an external storage device which is
-     * emulated. If true, the device does not have real external storage
-     * and certain system services such as the package manager use this
+     * emulated. If true, the device does not have real external storage, and the directory
+     * returned by {@link #getExternalStorageDirectory()} will be allocated using a portion of
+     * the internal storage system.
+     *
+     * <p>Certain system services, such as the package manager, use this
      * to determine where to install an application.
+     *
+     * <p>Emulated external storage may also be encrypted - see
+     * {@link android.app.admin.DevicePolicyManager#setStorageEncryption(
+     * android.content.ComponentName, boolean)} for additional details.
      */
     public static boolean isExternalStorageEmulated() {
         if (mIsExternalStorageEmulated == null) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 6ef680b..f9692da 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3680,7 +3680,7 @@
                     // flag coming from the child that initiated the invalidate
                     if (view != null) {
                         if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
-                                view.getSolidColor() == 0 && !view.isOpaque()) {
+                                view.getSolidColor() == 0) {
                             opaqueFlag = DIRTY;
                         }
                         if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index eb7269b..1316235 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3017,7 +3017,8 @@
     }
 
     /**
-     * Start an ActionMode for finding text in this WebView.
+     * Start an ActionMode for finding text in this WebView.  Only works if this
+     *              WebView is attached to the view system.
      * @param text If non-null, will be the initial text to search for.
      *             Otherwise, the last String searched for in this WebView will
      *             be used to start.
@@ -3027,7 +3028,7 @@
      */
     public boolean showFindDialog(String text, boolean showIme) {
         FindActionModeCallback callback = new FindActionModeCallback(mContext);
-        if (startActionMode(callback) == null) {
+        if (getParent() == null || startActionMode(callback) == null) {
             // Could not start the action mode, so end Find on page
             return false;
         }
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index f27ced8..942425af 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -16,6 +16,9 @@
 
 package android.webkit;
 
+import java.util.LinkedList;
+import java.util.Queue;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Canvas;
@@ -23,6 +26,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.util.FloatMath;
 import android.util.Log;
 import android.view.ScaleGestureDetector;
 import android.view.View;
@@ -112,6 +116,24 @@
     private float mZoomCenterY;
 
     /*
+     * Similar to mZoomCenterX(Y), these track the focus point of the scale
+     * gesture. The difference is these get updated every time when onScale is
+     * invoked no matter if a zooming really happens.
+     */
+    private float mFocusX;
+    private float mFocusY;
+
+    /*
+     * mFocusMovement keeps track of the total movement that the focus point
+     * has been through. Comparing to the difference of mCurrlen and mPrevLen,
+     * it determines if the gesture is for panning or zooming or both.
+     */
+    private static final int FOCUS_QUEUE_SIZE = 5;
+    private float mFocusMovementSum;
+    private Queue<Float> mFocusMovementQueue;
+
+
+    /*
      * These values represent the point around which the screen should be
      * centered after zooming. In other words it is used to determine the center
      * point of the visible document after the page has finished zooming. This
@@ -196,6 +218,8 @@
          * viewport size is.
          */
         setZoomOverviewWidth(WebView.DEFAULT_VIEWPORT_WIDTH);
+
+        mFocusMovementQueue = new LinkedList<Float>();
     }
 
     /**
@@ -715,10 +739,11 @@
     }
 
     private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener {
-
         public boolean onScaleBegin(ScaleGestureDetector detector) {
             mInitialZoomOverview = false;
             dismissZoomPicker();
+            mFocusMovementSum = 0;
+            mFocusMovementQueue.clear();
             mWebView.mViewManager.startZoom();
             mWebView.onPinchToZoomAnimationStart();
             return true;
@@ -729,6 +754,29 @@
             float scale = Math.max(
                     computeScaleWithLimits(detector.getScaleFactor() * mActualScale),
                     getZoomOverviewScale());
+
+            float prevFocusX = mFocusX;
+            float prevFocusY = mFocusY;
+            mFocusX = detector.getFocusX();
+            mFocusY = detector.getFocusY();
+            float focusDelta = (prevFocusX == 0 && prevFocusY == 0) ? 0 :
+                    FloatMath.sqrt((mFocusX - prevFocusX) * (mFocusX - prevFocusX)
+                                   + (mFocusY - prevFocusY) * (mFocusY - prevFocusY));
+            mFocusMovementSum += focusDelta;
+            mFocusMovementQueue.add(focusDelta);
+            if (mFocusMovementQueue.size() > FOCUS_QUEUE_SIZE) {
+                mFocusMovementSum -= mFocusMovementQueue.remove();
+            }
+            float deltaSpan = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan());
+
+            // If the user moves the fingers but keeps the same distance between them,
+            // we should do panning only.
+            if (mFocusMovementSum > deltaSpan) {
+                mFocusMovementSum = 0;
+                mFocusMovementQueue.clear();
+                return true;
+            }
+
             if (mPinchToZoomAnimating || willScaleTriggerZoom(scale)) {
                 mPinchToZoomAnimating = true;
                 // limit the scale change per step
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index d92588cb..17b3bda 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -477,8 +477,7 @@
                 break;
             case MotionEvent.ACTION_POINTER_DOWN: {
                 final int index = ev.getActionIndex();
-                final float x = ev.getX(index);
-                mLastMotionX = x;
+                mLastMotionX = ev.getX(index);
                 mActivePointerId = ev.getPointerId(index);
                 break;
             }
@@ -1446,6 +1445,7 @@
         super.setOverScrollMode(mode);
     }
 
+    @SuppressWarnings({"SuspiciousNameCombination"})
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 9002b1d..72b70bc 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1039,7 +1039,7 @@
      *
      * @return true if the popup is translated upwards to fit on screen
      */
-    boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
             int xoff, int yoff) {
 
         anchor.getLocationInWindow(mDrawingLocation);
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index bab469b..21c61bd 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -531,6 +531,8 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
+        boolean expandClipRegion = false;
+
         canvas.getClipBounds(stackInvalidateRect);
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -540,12 +542,22 @@
                     child.getAlpha() == 0f || child.getVisibility() != VISIBLE) {
                 lp.resetInvalidateRect();
             }
-            stackInvalidateRect.union(lp.getInvalidateRect());
+            Rect childInvalidateRect = lp.getInvalidateRect();
+            if (!childInvalidateRect.isEmpty()) {
+                expandClipRegion = true;
+                stackInvalidateRect.union(childInvalidateRect);
+            }
         }
-        canvas.save(Canvas.CLIP_SAVE_FLAG);
-        canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
-        super.dispatchDraw(canvas);
-        canvas.restore();
+
+        // We only expand the clip bounds if necessary.
+        if (expandClipRegion) {
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
+            super.dispatchDraw(canvas);
+            canvas.restore();
+        } else {
+            super.dispatchDraw(canvas);
+        }
     }
 
     private void onLayout() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 09c1ac5..13b9285f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4498,8 +4498,6 @@
         */
 
         canvas.restore();
-
-        updateCursorControllerPositions();
     }
 
     private void updateCursorsPositions() {
@@ -4557,15 +4555,7 @@
      * @hide
      */
     protected void updateCursorControllerPositions() {
-        // No need to create the controllers if they were not already
-        if (mInsertionPointCursorController != null &&
-                mInsertionPointCursorController.isShowing()) {
-            mInsertionPointCursorController.updatePosition();
-        }
-        if (mSelectionModifierCursorController != null &&
-                mSelectionModifierCursorController.isShowing()) {
-            mSelectionModifierCursorController.updatePosition();
-        }
+        // TODO remove
     }
 
     @Override
@@ -7356,14 +7346,9 @@
             }
 
             if (isTextEditable() || mTextIsSelectable) {
-                if (mScrollX != oldScrollX || mScrollY != oldScrollY) {
+                if (mScrollX != oldScrollX || mScrollY != oldScrollY) { // TODO remove
                     // Hide insertion anchor while scrolling. Leave selection.
-                    hideInsertionPointCursorController();
-                    // No need to create the controller, since there is nothing to update.
-                    if (mSelectionModifierCursorController != null &&
-                            mSelectionModifierCursorController.isShowing()) {
-                        mSelectionModifierCursorController.updatePosition();
-                    }
+                    hideInsertionPointCursorController(); // TODO any motion should hide it
                 }
 
                 if (touchIsFinished) {
@@ -7373,7 +7358,6 @@
                         handled |= imm != null && imm.showSoftInput(this, 0);
                     }
 
-
                     boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
                     if (!selectAllGotFocus && hasSelection()) {
                         startSelectionActionMode();
@@ -8653,26 +8637,31 @@
         }
     }
 
-    private class HandleView extends View implements ViewTreeObserver.OnScrollChangedListener {
+    private class HandleView extends View implements ViewTreeObserver.OnPreDrawListener {
         private Drawable mDrawable;
-        private final ScrollingPopupWindow mContainer;
-        private int mPositionX;
-        private int mPositionY;
+        private final PopupWindow mContainer;
+        // Position with respect to the parent TextView
+        private int mPositionX, mPositionY;
         private final CursorController mController;
         private boolean mIsDragging;
-        private float mTouchToWindowOffsetX;
-        private float mTouchToWindowOffsetY;
+        // Offset from touch position to mPosition
+        private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
         private float mHotspotX;
         // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
         private float mTouchOffsetY;
         // Where the touch position should be on the handle to ensure a maximum cursor visibility
         private float mIdealVerticalOffset;
-        private int mLastParentX;
-        private int mLastParentY;
+        // Parent's (TextView) position in window
+        private int mLastParentX, mLastParentY;
         private float mDownPositionX, mDownPositionY;
+        // PopupWindow container absolute position with respect to the enclosing window
         private int mContainerPositionX, mContainerPositionY;
-        private long mTouchTimer;
+        // Visible or not (scrolled off screen), whether or not this handle should be visible
+        private boolean mIsActive = false;
+        // The insertion handle can have an associated PastePopupMenu
         private boolean mIsInsertionHandle = false;
+        // Used to detect taps on the insertion handle, which will affect the PastePopupMenu
+        private long mTouchTimer;
         private PastePopupMenu mPastePopupWindow;
 
         // Touch-up filter: number of previous positions remembered
@@ -8684,12 +8673,12 @@
         private int mPreviousOffsetIndex = 0;
         private int mNumberPreviousOffsets = 0;
 
-        public void startTouchUpFilter(int offset) {
+        private void startTouchUpFilter(int offset) {
             mNumberPreviousOffsets = 0;
             addPositionToTouchUpFilter(offset);
         }
 
-        public void addPositionToTouchUpFilter(int offset) {
+        private void addPositionToTouchUpFilter(int offset) {
             if (mNumberPreviousOffsets > 0 &&
                     mPreviousOffsets[mPreviousOffsetIndex] == offset) {
                 // Make sure only actual changes of position are recorded.
@@ -8702,7 +8691,7 @@
             mNumberPreviousOffsets++;
         }
 
-        public void filterOnTouchUp() {
+        private void filterOnTouchUp() {
             final long now = SystemClock.uptimeMillis();
             int i = 0;
             int index = mPreviousOffsetIndex;
@@ -8725,16 +8714,17 @@
         public HandleView(CursorController controller, int pos) {
             super(TextView.this.mContext);
             mController = controller;
-            mContainer = new ScrollingPopupWindow(TextView.this.mContext, null,
+            mContainer = new PopupWindow(TextView.this.mContext, null,
                     com.android.internal.R.attr.textSelectHandleWindowStyle);
             mContainer.setSplitTouchEnabled(true);
             mContainer.setClippingEnabled(false);
             mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+            mContainer.setContentView(this);
 
-            setOrientation(pos);
+            setPosition(pos);
         }
 
-        public void setOrientation(int pos) {
+        private void setPosition(int pos) {
             int handleWidth;
             switch (pos) {
                 case LEFT: {
@@ -8774,38 +8764,48 @@
             }
 
             final int handleHeight = mDrawable.getIntrinsicHeight();
-
             mTouchOffsetY = -0.3f * handleHeight;
             mIdealVerticalOffset = 0.7f * handleHeight;
+
             invalidate();
         }
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            setMeasuredDimension(mDrawable.getIntrinsicWidth(),
-                    mDrawable.getIntrinsicHeight());
+            setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
         }
 
         public void show() {
-            if (!isPositionVisible()) {
-                hide();
-                return;
-            }
-            mContainer.setContentView(this);
-            mContainerPositionX = mPositionX;
-            mContainerPositionY = mPositionY - TextView.this.getHeight();
-            mContainer.showAsDropDown(TextView.this, mContainerPositionX, mContainerPositionY);
+            updateContainerPosition();
+            if (isShowing()) {
+                mContainer.update(mContainerPositionX, mContainerPositionY,
+                        mRight - mLeft, mBottom - mTop);
 
-            // Hide paste view when handle is moved on screen.
+                hidePastePopupWindow();
+            } else {
+                mContainer.showAtLocation(TextView.this, 0,
+                        mContainerPositionX, mContainerPositionY);
+
+                mIsActive = true;
+
+                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+                vto.addOnPreDrawListener(this);
+            }
+        }
+
+        private void dismiss() {
+            mIsDragging = false;
+            mContainer.dismiss();
             hidePastePopupWindow();
         }
 
         public void hide() {
-            mIsDragging = false;
-            mContainer.dismiss();
-            hidePastePopupWindow();
+            dismiss();
+
+            mIsActive = false;
+
             ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-            vto.removeOnScrollChangedListener(this);
+            vto.removeOnPreDrawListener(this);
         }
 
         public boolean isShowing() {
@@ -8856,44 +8856,59 @@
         private void moveTo(int x, int y) {
             mPositionX = x - TextView.this.mScrollX;
             mPositionY = y - TextView.this.mScrollY;
-            if (isPositionVisible()) {
-                int[] coords = null;
-                if (mContainer.isShowing()) {
-                    final int containerPositionX = mPositionX;
-                    final int containerPositionY = mPositionY - TextView.this.getHeight();
 
-                    if (containerPositionX != mContainerPositionX || 
-                        containerPositionY != mContainerPositionY) {
-                        mContainerPositionX = containerPositionX;
-                        mContainerPositionY = containerPositionY;
+            if (mIsDragging) {
+                TextView.this.getLocationInWindow(mTempCoords);
+                if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
+                    mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
+                    mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
+                    mLastParentX = mTempCoords[0];
+                    mLastParentY = mTempCoords[1];
+                }
+                // Hide paste popup window as soon as the handle is dragged.
+                hidePastePopupWindow();
+            }
+        }
 
-                        mContainer.update(TextView.this, mContainerPositionX, mContainerPositionY,
-                                mRight - mLeft, mBottom - mTop);
+        /**
+         * Updates the global container's position.
+         * @return whether or not the position has actually changed
+         */
+        private boolean updateContainerPosition() {
+            // TODO Prevent this using different HandleView subclasses
+            mController.updateOffset(this, mController.getCurrentOffset(this));
+            TextView.this.getLocationInWindow(mTempCoords);
+            final int containerPositionX = mTempCoords[0] + mPositionX;
+            final int containerPositionY = mTempCoords[1] + mPositionY;
 
-                        // Hide paste popup window as soon as a scroll occurs.
-                        hidePastePopupWindow();
+            if (containerPositionX != mContainerPositionX ||
+                containerPositionY != mContainerPositionY) {
+                mContainerPositionX = containerPositionX;
+                mContainerPositionY = containerPositionY;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean onPreDraw() {
+            if (updateContainerPosition()) {
+                if (isPositionVisible()) {
+                    mContainer.update(mContainerPositionX, mContainerPositionY,
+                            mRight - mLeft, mBottom - mTop);
+
+                    if (mIsActive && !isShowing()) {
+                        show();
                     }
                 } else {
-                    show();
+                    if (isShowing()) {
+                        dismiss();
+                    }
                 }
 
-                if (mIsDragging) {
-                    if (coords == null) {
-                        coords = mTempCoords;
-                        TextView.this.getLocationInWindow(coords);
-                    }
-                    if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
-                        mTouchToWindowOffsetX += coords[0] - mLastParentX;
-                        mTouchToWindowOffsetY += coords[1] - mLastParentY;
-                        mLastParentX = coords[0];
-                        mLastParentY = coords[1];
-                    }
-                    // Hide paste popup window as soon as the handle is dragged.
-                    hidePastePopupWindow();
-                }
-            } else {
-                hide();
+                // Hide paste popup as soon as the view is scrolled or moved
+                hidePastePopupWindow();
             }
+            return true;
         }
 
         @Override
@@ -8979,7 +8994,7 @@
             return mIsDragging;
         }
 
-        void positionAtCursor(final int offset) {
+        void positionAtCursor(int offset) {
             addPositionToTouchUpFilter(offset);
             final int width = mDrawable.getIntrinsicWidth();
             final int height = mDrawable.getIntrinsicHeight();
@@ -9013,50 +9028,6 @@
                 mPastePopupWindow.hide();
             }
         }
-
-        /**
-         * A popup window, attached to a view, and that listens to scroll events in its anchors'
-         * view hierarchy, so that it is automatically moved on such events.
-         */
-        private class ScrollingPopupWindow extends PopupWindow {
-
-            private int[] mDrawingLocations = new int[2];
-
-            public ScrollingPopupWindow(Context context, AttributeSet attrs, int defStyle) {
-                super(context, attrs, defStyle);
-            }
-
-            @Override
-            public boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
-                    int xoff, int yoff) {
-                anchor.getLocationInWindow(mDrawingLocations);
-                p.x = mDrawingLocations[0] + xoff;
-                p.y = mDrawingLocations[1] + anchor.getHeight() + yoff;
-
-                // Hide paste popup as soon as the view is scrolled.
-                hidePastePopupWindow();
-
-                if (!isPositionVisible()) {
-                    dismiss();
-                    onHandleBecomeInvisible();
-                }
-
-                return false;
-            }
-        }
-
-        public void onScrollChanged() {
-            if (isPositionVisible()) {
-                show();
-                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-                vto.removeOnScrollChangedListener(this);
-            }
-        }
-
-        public void onHandleBecomeInvisible() {
-            ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-            vto.addOnScrollChangedListener(this);
-        }
     }
 
     private class InsertionPointCursorController implements CursorController {
@@ -9074,7 +9045,7 @@
         }
 
         public void show(int delayBeforePaste) {
-            updatePosition();
+            getHandle().show();
             hideDelayed();
             removePastePopupCallback();
             final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
@@ -9213,7 +9184,6 @@
             if (mEndHandle == null) mEndHandle = new HandleView(this, HandleView.RIGHT);
 
             mIsShowing = true;
-            updatePosition();
 
             mStartHandle.show();
             mEndHandle.show();
diff --git a/core/res/res/raw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..492658d
--- /dev/null
+++ b/core/res/res/raw-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
+    <title>New incognito tab</title>
+  </head>
+  <body>
+    <p><strong>You've gone incognito</strong>. Pages you view in this tab
+      won't appear in your browser history or search history, and they won't
+      leave other traces, like cookies, on your device after you close the
+      incognito tab. Any files you download or bookmarks you create will be
+      preserved, however.</p>
+
+    <p><strong>Going incognito doesn't affect the behavior of other people,
+      servers, or software. Be wary of:</strong></p>
+
+    <ul>
+      <li>Websites that collect or share information about you</li>
+      <li>Internet service providers or employers that track the pages you visit</li>
+      <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+      <li>Surveillance by secret agents</li>
+      <li>People standing behind you</li>
+    </ul>
+  </body>
+</html>
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
index bfa6c36a..3f172e6 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
@@ -38,8 +38,8 @@
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
-        android:layout_marginLeft="123dip"
-        android:layout_marginTop="16dip"
+        android:layout_marginLeft="131dip"
+        android:layout_marginTop="13dip"
         android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
         android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
         android:adjustViewBounds="true"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
index eda19b7..42940be 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
@@ -51,7 +51,7 @@
                 android:stackFromBottom="true"
                 android:fadingEdge="vertical"
                 android:scrollbars="none"
-                android:fadingEdgeLength="30dip"
+                android:fadingEdgeLength="20dip"
                 android:listSelector="@drawable/recents_thumbnail_bg_selector"
             />
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 6c9f48f..db14e53 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -28,10 +28,12 @@
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Arc2D;
 import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
 
 /**
  * Delegate implementing the native methods of android.graphics.Path
@@ -331,58 +333,91 @@
 
     @LayoutlibDelegate
     /*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addOval is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        pathDelegate.mPath.append(new Ellipse2D.Float(
+                oval.left, oval.top, oval.width(), oval.height()), false);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addCircle is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        // because x/y is the center of the circle, need to offset this by the radius
+        pathDelegate.mPath.append(new Ellipse2D.Float(
+                x - radius, y - radius, radius * 2, radius * 2), false);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addArc(int nPath, RectF oval,
             float startAngle, float sweepAngle) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addArc is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        // because x/y is the center of the circle, need to offset this by the radius
+        pathDelegate.mPath.append(new Arc2D.Float(
+                oval.left, oval.top, oval.width(), oval.height(),
+                startAngle, sweepAngle, Arc2D.OPEN), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(int nPath, RectF rect,
-            float rx, float ry, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addRoundRect is not supported.", null, null /*data*/);
+    /*package*/ static void native_addRoundRect(
+            int nPath, RectF rect, float rx, float ry, int dir) {
+
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        pathDelegate.mPath.append(new RoundRectangle2D.Float(
+                rect.left, rect.top, rect.width(), rect.height(), rx * 2, ry * 2), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(int nPath, RectF r, float[] radii, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addRoundRect is not supported.", null, null /*data*/);
+    /*package*/ static void native_addRoundRect(int nPath, RectF rect, float[] radii, int dir) {
+        // Java2D doesn't support different rounded corners in each corner, so just use the
+        // first value.
+        native_addRoundRect(nPath, rect, radii[0], radii[1], dir);
+
+        // there can be a case where this API is used but with similar values for all corners, so
+        // in that case we don't warn.
+        // we only care if 2 corners are different so just compare to the next one.
+        for (int i = 0 ; i < 3 ; i++) {
+            if (radii[i * 2] != radii[(i + 1) * 2] || radii[i * 2 + 1] != radii[(i + 1) * 2 + 1]) {
+                Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                        "Different corner sizes are not supported in Path.addRoundRect.",
+                        null, null /*data*/);
+                break;
+            }
+        }
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addPath is not supported.", null, null /*data*/);
+        addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src) {
-        native_addPath(nPath, src, 0, 0);
+        addPath(nPath, src, null /*transform*/);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src, int matrix) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addPath is not supported.", null, null /*data*/);
+        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+        if (matrixDelegate == null) {
+            return;
+        }
+
+        addPath(nPath, src, matrixDelegate.getAffineTransform());
     }
 
     @LayoutlibDelegate
@@ -487,6 +522,26 @@
         return null;
     }
 
+    private static void addPath(int destPath, int srcPath, AffineTransform transform) {
+        Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
+        if (destPathDelegate == null) {
+            return;
+        }
+
+        Path_Delegate srcPathDelegate = sManager.getDelegate(srcPath);
+        if (srcPathDelegate == null) {
+            return;
+        }
+
+        if (transform != null) {
+            destPathDelegate.mPath.append(
+                    srcPathDelegate.mPath.getPathIterator(transform), false);
+        } else {
+            destPathDelegate.mPath.append(srcPathDelegate.mPath, false);
+        }
+    }
+
+
     /**
      * Returns whether the path is empty.
      * @return true if the path is empty.
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 acc7379..e6e9647 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -192,7 +192,7 @@
                 Capability.UNBOUND_RENDERING,
                 Capability.CUSTOM_BACKGROUND_COLOR,
                 Capability.RENDER,
-                Capability.LAYOUT_ONLY,
+                //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
                 Capability.EMBEDDED_LAYOUT,
                 Capability.VIEW_MANIPULATION,
                 Capability.PLAY_ANIMATION,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index c1d7600..138a455 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -412,9 +412,7 @@
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
-        }
-
-        if (RenderResources.REFERENCE_NULL.equals(s)) {
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
             return defValue;
         }
 
@@ -486,23 +484,32 @@
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
-        }
-
-        if (RenderResources.REFERENCE_NULL.equals(s)) {
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
             return defValue;
         }
 
-        // FIXME huh?
+        if (ResourceHelper.stringToFloat(s, mValue)) {
+            float f = mValue.getDimension(mBridgeResources.mMetrics);
 
-        float f = getDimension(index, defValue);
-        final int res = (int)(f+0.5f);
-        if (res != 0) return res;
-        if (f == 0) return 0;
-        if (f > 0) return 1;
+            if (f < 0) {
+                // negative values are not allowed in pixel dimensions
+                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                        "Negative pixel dimension: " + s,
+                        null, null /*data*/);
+                return defValue;
+            }
 
-        Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
-                "Can't convert to dimension: " + Integer.toString(index),
-                null, null /*data*/);
+            if (f == 0) return 0;
+            if (f < 1) return 1;
+
+            return (int)(f+0.5f);
+        }
+
+        // looks like we were unable to resolve the dimension value
+        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                String.format(
+                    "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+                    s, mNames[index]), null /*data*/);
 
         return defValue;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 69f46e6..649160e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -377,7 +377,7 @@
         }
 
         // check the first character
-        if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+        if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.' && buf[0] != '-') {
             return false;
         }