XML attribute for overscrolling behavior
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 57fdd8b..e5db120 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1504,6 +1504,31 @@
      * @hide
      */
     private static final int PREPRESSED             = 0x02000000;
+    
+    /**
+     * Always allow a user to overscroll this view, provided it is a
+     * view that can scroll.
+     */
+    private static final int OVERSCROLL_ALWAYS = 0;
+    
+    /**
+     * Allow a user to overscroll this view only if the content is large
+     * enough to meaningfully scroll, provided it is a view that can scroll.
+     */
+    private static final int OVERSCROLL_IF_CONTENT_SCROLLS = 1;
+    
+    /**
+     * Never allow a user to overscroll this view.
+     */
+    private static final int OVERSCROLL_NEVER = 2;
+    
+    /**
+     * Controls the overscroll mode for this view.
+     * See {@link #overscrollBy(int, int, int, int, int, int, int, int)},
+     * {@link #OVERSCROLL_ALWAYS}, {@link #OVERSCROLL_IF_CONTENT_SCROLLS},
+     * and {@link #OVERSCROLL_NEVER}.
+     */
+    private int mOverscrollMode = OVERSCROLL_ALWAYS;
 
     /**
      * The parent this view is attached to.
@@ -2053,6 +2078,9 @@
                         });
                     }
                     break;
+                case R.styleable.View_overscrollMode:
+                    mOverscrollMode = a.getInt(attr, OVERSCROLL_ALWAYS);
+                    break;
             }
         }
 
@@ -8573,43 +8601,59 @@
             int scrollX, int scrollY,
             int scrollRangeX, int scrollRangeY,
             int maxOverscrollX, int maxOverscrollY) {
-        // Scale the scroll amount if we're in the dropoff zone
-        final int dropoffX = maxOverscrollX / 2;
-        final int dropoffLeft = -dropoffX;
-        final int dropoffRight = dropoffX + scrollRangeX;
-        int newScrollX;
-        if ((scrollX < dropoffLeft && deltaX < 0) ||
-                (scrollX > dropoffRight && deltaX > 0)) {
-            newScrollX = scrollX + deltaX / 2;
-        } else {
-            newScrollX = scrollX + deltaX;
-            if (newScrollX > dropoffRight && deltaX > 0) {
-                int extra = newScrollX - dropoffRight;
-                newScrollX = dropoffRight + extra / 2;
-            } else if (newScrollX < dropoffLeft && deltaX < 0) {
-                int extra = newScrollX - dropoffLeft;
-                newScrollX = dropoffLeft + extra / 2;
-            }
-        }
+        final int overscrollMode = mOverscrollMode;
+        final boolean canScrollHorizontal = 
+                computeHorizontalScrollRange() > computeHorizontalScrollExtent();
+        final boolean canScrollVertical = 
+                computeVerticalScrollRange() > computeVerticalScrollExtent();
+        final boolean overscrollHorizontal = overscrollMode == OVERSCROLL_ALWAYS ||
+                (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
+        final boolean overscrollVertical = overscrollMode == OVERSCROLL_ALWAYS ||
+                (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
         
-        final int dropoffY = maxOverscrollY / 2;
-        final int dropoffTop = -dropoffY;
-        final int dropoffBottom = dropoffY + scrollRangeY;
-        int newScrollY;
-        if ((scrollY < dropoffTop && deltaY < 0) ||
-                (scrollY > dropoffBottom && deltaY > 0)) {
-            newScrollY = scrollY + deltaY / 2;
-        } else {
-            newScrollY = scrollY + deltaY;
-            if (newScrollY > dropoffBottom && deltaY > 0) {
-                int extra = newScrollY - dropoffBottom;
-                newScrollY = dropoffBottom + extra / 2;
-            } else if (newScrollY < dropoffTop && deltaY < 0) {
-                int extra = newScrollY - dropoffTop;
-                newScrollY = dropoffTop + extra / 2;
+        int newScrollX = scrollX + deltaX;
+        if (overscrollHorizontal) {
+            // Scale the scroll amount if we're in the dropoff zone
+            final int dropoffX = maxOverscrollX / 2;
+            final int dropoffLeft = -dropoffX;
+            final int dropoffRight = dropoffX + scrollRangeX;
+            if ((scrollX < dropoffLeft && deltaX < 0) ||
+                    (scrollX > dropoffRight && deltaX > 0)) {
+                newScrollX = scrollX + deltaX / 2;
+            } else {
+                if (newScrollX > dropoffRight && deltaX > 0) {
+                    int extra = newScrollX - dropoffRight;
+                    newScrollX = dropoffRight + extra / 2;
+                } else if (newScrollX < dropoffLeft && deltaX < 0) {
+                    int extra = newScrollX - dropoffLeft;
+                    newScrollX = dropoffLeft + extra / 2;
+                }
             }
+        } else {
+            maxOverscrollX = 0;
         }
 
+        int newScrollY = scrollY + deltaY;
+        if (overscrollVertical) {
+            final int dropoffY = maxOverscrollY / 2;
+            final int dropoffTop = -dropoffY;
+            final int dropoffBottom = dropoffY + scrollRangeY;
+            if ((scrollY < dropoffTop && deltaY < 0) ||
+                    (scrollY > dropoffBottom && deltaY > 0)) {
+                newScrollY = scrollY + deltaY / 2;
+            } else {
+                if (newScrollY > dropoffBottom && deltaY > 0) {
+                    int extra = newScrollY - dropoffBottom;
+                    newScrollY = dropoffBottom + extra / 2;
+                } else if (newScrollY < dropoffTop && deltaY < 0) {
+                    int extra = newScrollY - dropoffTop;
+                    newScrollY = dropoffTop + extra / 2;
+                }
+            }
+        } else {
+            maxOverscrollY = 0;
+        }
+        
         // Clamp values if at the limits and record
         final int left = -maxOverscrollX;
         final int right = maxOverscrollX + scrollRangeX;
@@ -8636,8 +8680,8 @@
         
         // Bump the device with some haptic feedback if we're at the edge
         // and didn't start there.
-        if ((clampedX && scrollX != left && scrollX != right) ||
-                (clampedY && scrollY != top && scrollY != bottom)) {
+        if ((overscrollHorizontal && clampedX && scrollX != left && scrollX != right) ||
+                (overscrollVertical && clampedY && scrollY != top && scrollY != bottom)) {
             performHapticFeedback(HapticFeedbackConstants.SCROLL_BARRIER);
         }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4c77bdc..254efe7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2589,7 +2589,8 @@
                 if (trackMotionScroll(delta, delta)) {
                     if (motionView != null) {
                         // Tweak the scroll for how far we overshot
-                        mScrollY -= delta - (motionView.getTop() - oldTop);
+                        int overshoot = -(delta - (motionView.getTop() - oldTop));
+                        overscrollBy(0, overshoot, 0, mScrollY, 0, 0, 0, getOverscrollMax());
                     }
                     float vel = scroller.getCurrVelocity();
                     if (delta > 0) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0f6a5c1..ff93984 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1307,6 +1307,19 @@
              <code>public void sayHello(View v)</code> method of your context
              (typically, your Activity). -->
         <attr name="onClick" format="string" />
+
+        <!-- Defines overscrolling behavior. This property is used only if the
+             View is scrollable. Overscrolling is the ability for the user to
+             scroll a View beyond its content boundaries into empty space. -->
+        <attr name="overscrollMode">
+            <!-- Always allow the user to overscroll the content. -->
+            <enum name="always" value="0" />
+            <!-- Only allow the user to overscroll content if the content is large
+                 enough to meaningfully scroll. -->
+            <enum name="ifContentScrolls" value="1" />
+            <!-- Never overscroll. -->
+            <enum name="never" value="2" />
+        </attr>
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 82c02eb5..b334337 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1230,6 +1230,7 @@
   <public type="attr" name="installLocation" id="0x010102b7" />
   <public type="attr" name="safeMode" id="0x010102b8" />
   <public type="attr" name="webTextViewStyle" id="0x010102b9" />
+  <public type="attr" name="overscrollMode" id="0x010102ba" />
 
   <public type="anim" name="cycle_interpolator" id="0x010a000c" />