Fixing errors in position information of scrollable views reported for accessibility.

1. ScrollView/HorizontalScroll view were reporting only the scroll X and Y but
   failed to convey the max scroll along X and Y so the position can be determined.

2. WebView was not reporting correctly its scroll position for accessibility.

3. Some descendants of AdapterView were reporting incorrect position information.

4. Updated the accessibility docs with some details about the scroll information.

5. Cleaned up duplicated code.

bug:5412132
bug:5412265

Change-Id: I165e73ecde027dad811425b9f395a3f758c923ba
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8e5aefd..e0192ae 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4001,23 +4001,13 @@
         event.setEnabled(isEnabled());
         event.setContentDescription(mContentDescription);
 
-        final int eventType = event.getEventType();
-        switch (eventType) {
-            case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
-                if (mAttachInfo != null) {
-                    ArrayList<View> focusablesTempList = mAttachInfo.mFocusablesTempList;
-                    getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD,
-                            FOCUSABLES_ALL);
-                    event.setItemCount(focusablesTempList.size());
-                    event.setCurrentItemIndex(focusablesTempList.indexOf(this));
-                    focusablesTempList.clear();
-                }
-            } break;
-            case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
-                event.setScrollX(mScrollX);
-                event.setScrollY(mScrollY);
-                event.setItemCount(getHeight());
-            } break;
+        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && mAttachInfo != null) {
+            ArrayList<View> focusablesTempList = mAttachInfo.mFocusablesTempList;
+            getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD,
+                    FOCUSABLES_ALL);
+            event.setItemCount(focusablesTempList.size());
+            event.setCurrentItemIndex(focusablesTempList.indexOf(this));
+            focusablesTempList.clear();
         }
     }
 
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 91fbb0e..25bc559 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -79,6 +79,16 @@
  *   <li>{@link #isPassword()} - Whether the source is password.</li>
  *   <li>{@link #isChecked()} - Whether the source is checked.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
+ *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getItemCount()} - The total items of the source
+ *       (for descendants of AdapterView).</li>
  * </ul>
  * </p>
  * <p>
@@ -97,6 +107,16 @@
  *   <li>{@link #isPassword()} - Whether the source is password.</li>
  *   <li>{@link #isChecked()} - Whether the source is checked.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
+ *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getItemCount()} - The total items of the source
+ *       (for descendants of AdapterView).</li>
  * </ul>
  * </p>
  * <p>
@@ -117,6 +137,16 @@
  *   <li>{@link #getItemCount()} - The number of selectable items of the source.</li>
  *   <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
+ *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getItemCount()} - The total items of the source
+ *       (for descendants of AdapterView).</li>
  * </ul>
  * </p>
  * <p>
@@ -137,6 +167,16 @@
  *   <li>{@link #getItemCount()} - The number of focusable items on the screen.</li>
  *   <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
+ *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getItemCount()} - The total items of the source
+ *       (for descendants of AdapterView).</li>
  * </ul>
  * </p>
  * <p>
@@ -218,18 +258,17 @@
  *   <li>{@link #getEventTime()}  - The event time.</li>
  *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
  *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- *   <li>{@link #getScrollX()} - The horizontal offset of the source
- *                                (without descendants of AdapterView)).</li>
- *   <li>{@link #getScrollY()} - The vertical offset of the source
- *                                (without descendants of AdapterView)).</li>
- *   <li>{@link #getFromIndex()} - The index of the first visible item of the source
- *                                 (for descendants of AdapterView).</li>
- *   <li>{@link #getToIndex()} - The index of the last visible item of the source
- *                               (for descendants of AdapterView).</li>
- *   <li>{@link #getItemCount()} - The total items of the source (for descendants of AdapterView)
- *                                 or the height of the source in pixels (all other cases).</li>
- *   <li>{@link #getText()} - Text for providing more context.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
+ *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getItemCount()} - The total items of the source
+ *       (for descendants of AdapterView).</li>
  * </ul>
  * <em>Note:</em> This event type is not dispatched to descendants though
  * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
@@ -334,6 +373,16 @@
  *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
  *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
+ *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getItemCount()} - The total items of the source
+ *       (for descendants of AdapterView).</li>
  * </ul>
  * </p>
  * <b>View hover exit</b> - represents the event of stopping to hover
@@ -350,6 +399,16 @@
  *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
  *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
+ *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
+ *       (without descendants of AdapterView).</li>
+ *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
+ *       inclusive (for descendants of AdapterView).</li>
+ *   <li>{@link #getItemCount()} - The total items of the source
+ *       (for descendants of AdapterView).</li>
  * </ul>
  * </p>
  * <p>
@@ -816,6 +875,8 @@
         record.mToIndex = parcel.readInt();
         record.mScrollX = parcel.readInt();
         record.mScrollY =  parcel.readInt();
+        record.mMaxScrollX = parcel.readInt();
+        record.mMaxScrollY =  parcel.readInt();
         record.mAddedCount = parcel.readInt();
         record.mRemovedCount = parcel.readInt();
         record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
@@ -868,6 +929,8 @@
         parcel.writeInt(record.mToIndex);
         parcel.writeInt(record.mScrollX);
         parcel.writeInt(record.mScrollY);
+        parcel.writeInt(record.mMaxScrollX);
+        parcel.writeInt(record.mMaxScrollY);
         parcel.writeInt(record.mAddedCount);
         parcel.writeInt(record.mRemovedCount);
         TextUtils.writeToParcel(record.mClassName, parcel, flags);
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index afd7473..fe06d98 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -73,6 +73,8 @@
     int mToIndex = UNDEFINED;
     int mScrollX = UNDEFINED;
     int mScrollY = UNDEFINED;
+    int mMaxScrollX = UNDEFINED;
+    int mMaxScrollY = UNDEFINED;
 
     int mAddedCount= UNDEFINED;
     int mRemovedCount = UNDEFINED;
@@ -348,18 +350,18 @@
     }
 
     /**
-     * Gets the scroll position of the source along the X axis.
+     * Gets the scroll offset of the source left edge in pixels.
      *
-     * @return The scroll along the X axis.
+     * @return The scroll.
      */
     public int getScrollX() {
         return mScrollX;
     }
 
     /**
-     * Sets the scroll position of the source along the X axis.
+     * Sets the scroll offset of the source left edge in pixels.
      *
-     * @param scrollX The scroll along the X axis.
+     * @param scrollX The scroll.
      */
     public void setScrollX(int scrollX) {
         enforceNotSealed();
@@ -367,18 +369,18 @@
     }
 
     /**
-     * Gets the scroll position of the source along the Y axis.
+     * Gets the scroll offset of the source top edge in pixels.
      *
-     * @return The scroll along the Y axis.
+     * @return The scroll.
      */
     public int getScrollY() {
         return mScrollY;
     }
 
     /**
-     * Sets the scroll position of the source along the Y axis.
+     * Sets the scroll offset of the source top edge in pixels.
      *
-     * @param scrollY The scroll along the Y axis.
+     * @param scrollY The scroll.
      */
     public void setScrollY(int scrollY) {
         enforceNotSealed();
@@ -386,6 +388,51 @@
     }
 
     /**
+     * Gets the max scroll offset of the source left edge in pixels.
+     *
+     * @return The max scroll.
+     *
+     * @hide
+     */
+    public int getMaxScrollX() {
+        return mMaxScrollX;
+    }
+    /**
+     * Sets the max scroll offset of the source left edge in pixels.
+     *
+     * @param maxScrollX The max scroll.
+     *
+     * @hide
+     */
+    public void setMaxScrollX(int maxScrollX) {
+        enforceNotSealed();
+        mMaxScrollX = maxScrollX;
+    }
+
+    /**
+     * Gets the max scroll offset of the source top edge in pixels.
+     *
+     * @return The max scroll.
+     *
+     * @hide
+     */
+    public int getMaxScrollY() {
+        return mMaxScrollY;
+    }
+
+    /**
+     * Sets the max scroll offset of the source top edge in pixels.
+     *
+     * @param maxScrollY The max scroll.
+     *
+     * @hide
+     */
+    public void setMaxScrollY(int maxScrollY) {
+        enforceNotSealed();
+        mMaxScrollY = maxScrollY;
+    }
+
+    /**
      * Gets the number of added characters.
      *
      * @return The number of added characters.
@@ -658,6 +705,8 @@
         mToIndex = record.mToIndex;
         mScrollX = record.mScrollX;
         mScrollY = record.mScrollY;
+        mMaxScrollX = record.mMaxScrollX;
+        mMaxScrollY = record.mMaxScrollY;
         mAddedCount = record.mAddedCount;
         mRemovedCount = record.mRemovedCount;
         mClassName = record.mClassName;
@@ -682,6 +731,8 @@
         mToIndex = UNDEFINED;
         mScrollX = UNDEFINED;
         mScrollY = UNDEFINED;
+        mMaxScrollX = UNDEFINED;
+        mMaxScrollY = UNDEFINED;
         mAddedCount = UNDEFINED;
         mRemovedCount = UNDEFINED;
         mClassName = null;
@@ -711,6 +762,8 @@
         builder.append("; ToIndex: " + mToIndex);
         builder.append("; ScrollX: " + mScrollX);
         builder.append("; ScrollY: " + mScrollY);
+        builder.append("; MaxScrollX: " + mMaxScrollX);
+        builder.append("; MaxScrollY: " + mMaxScrollY);
         builder.append("; AddedCount: " + mAddedCount);
         builder.append("; RemovedCount: " + mRemovedCount);
         builder.append("; ParcelableData: " + mParcelableData);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index eaed9fe..87c89c6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -77,7 +77,9 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
@@ -1303,6 +1305,31 @@
     }
 
     @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setScrollable(isScrollableForAccessibility());
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setScrollable(isScrollableForAccessibility());
+        event.setScrollX(mScrollX);
+        event.setScrollY(mScrollY);
+        final int convertedContentWidth = contentToViewX(getContentWidth());
+        final int adjustedViewWidth = getWidth() - mPaddingLeft - mPaddingRight;
+        event.setMaxScrollX(Math.max(convertedContentWidth - adjustedViewWidth, 0));
+        final int convertedContentHeight = contentToViewY(getContentHeight());
+        final int adjustedViewHeight = getHeight() - mPaddingTop - mPaddingBottom;
+        event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
+    }
+
+    private boolean isScrollableForAccessibility() {
+        return (contentToViewX(getContentWidth()) > getWidth() - mPaddingLeft - mPaddingRight
+                || contentToViewY(getContentHeight()) > getHeight() - mPaddingTop - mPaddingBottom);
+    }
+
+    @Override
     public void setOverScrollMode(int mode) {
         super.setOverScrollMode(mode);
         if (mode != OVER_SCROLL_NEVER) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7b8c7f2..c218f23 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1270,40 +1270,24 @@
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setScrollable(true);
-    }
-
-    @Override
     public void sendAccessibilityEvent(int eventType) {
         // Since this class calls onScrollChanged even if the mFirstPosition and the
         // child count have not changed we will avoid sending duplicate accessibility
         // events.
         if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
-            final int lastPosition = mFirstPosition + getChildCount();
-            if (mLastAccessibilityScrollEventFromIndex == mFirstPosition
-                    && mLastAccessibilityScrollEventToIndex == lastPosition) {
+            final int firstVisiblePosition = getFirstVisiblePosition();
+            final int lastVisiblePosition = getLastVisiblePosition();
+            if (mLastAccessibilityScrollEventFromIndex == firstVisiblePosition
+                    && mLastAccessibilityScrollEventToIndex == lastVisiblePosition) {
                 return;   
             } else {
-                mLastAccessibilityScrollEventFromIndex = mFirstPosition;
-                mLastAccessibilityScrollEventToIndex = lastPosition;       
+                mLastAccessibilityScrollEventFromIndex = firstVisiblePosition;
+                mLastAccessibilityScrollEventToIndex = lastVisiblePosition;
             }
         }
         super.sendAccessibilityEvent(eventType);
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setScrollable(true);
-        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
-            event.setFromIndex(mFirstPosition);
-            event.setToIndex(mFirstPosition +  getChildCount());
-            event.setItemCount(mItemCount);
-        }
-    }
-
     /**
      * Indicates whether the children's drawing cache is used during a scroll.
      * By default, the drawing cache is enabled but this will consume more memory.
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 61c5dd4..fd19b5f 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -29,6 +29,7 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 
 /**
@@ -881,19 +882,10 @@
 
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
-            // This is an exceptional case which occurs when a window gets the
-            // focus and sends a focus event via its focused child to announce
-            // current focus/selection. AdapterView fires selection but not focus
-            // events so we change the event type here.
-            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
-                event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
-            }
-        }
-
         View selectedView = getSelectedView();
-        if (selectedView != null && selectedView.getVisibility() == VISIBLE) {
-            getSelectedView().dispatchPopulateAccessibilityEvent(event);
+        if (selectedView != null && selectedView.getVisibility() == VISIBLE
+                && selectedView.dispatchPopulateAccessibilityEvent(event)) {
+            return true;
         }
         return false;
     }
@@ -913,19 +905,32 @@
     }
 
     @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setScrollable(isScrollableForAccessibility());
+        View selectedView = getSelectedView();
+        if (selectedView != null) {
+            info.setEnabled(selectedView.isEnabled());
+        }
+    }
+
+    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-
+        event.setScrollable(isScrollableForAccessibility());
         View selectedView = getSelectedView();
         if (selectedView != null) {
             event.setEnabled(selectedView.isEnabled());
         }
-        event.setItemCount(getCount());
-        event.setCurrentItemIndex(getSelectedItemPosition());
-        if (getChildCount() > 0) {
-            event.setFromIndex(getFirstVisiblePosition());
-            event.setToIndex(getLastVisiblePosition());
-        }
+        event.setFromIndex(getFirstVisiblePosition());
+        event.setToIndex(getLastVisiblePosition());
+        event.setItemCount(getAdapter().getCount());
+    }
+
+    private boolean isScrollableForAccessibility() {
+        final int itemCount = getAdapter().getCount();
+        return itemCount > 0
+            && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1);
     }
 
     @Override
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index a0eba9a..5e37fa8 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -32,8 +32,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Transformation;
 
 import com.android.internal.R;
@@ -354,23 +352,6 @@
         return child.getMeasuredHeight();
     }
 
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setScrollable(true);
-    }
-
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setScrollable(true);
-        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
-            event.setFromIndex(mFirstPosition);
-            event.setToIndex(mFirstPosition +  getChildCount());
-            event.setItemCount(mItemCount);
-        }
-    }
-
     /**
      * Tracks a motion scroll. In reality, this is used to do just about any
      * movement to items (touch scroll, arrow-key scroll, set an item as selected).
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 324dfd7..57701ae 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -716,13 +716,17 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        info.setScrollable(true);
+        info.setScrollable(getScrollRange() > 0);
     }
 
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-        event.setScrollable(true);
+        event.setScrollable(getScrollRange() > 0);
+        event.setScrollX(mScrollX);
+        event.setScrollY(mScrollY);
+        event.setMaxScrollX(getScrollRange());
+        event.setMaxScrollY(mScrollY);
     }
 
     private int getScrollRange() {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 42e27b1..9ef1aa1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1997,31 +1997,6 @@
         }
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-
-        // If the item count is less than 15 then subtract disabled items from the count and
-        // position. Otherwise ignore disabled items.
-        int itemCount = 0;
-        int currentItemIndex = getSelectedItemPosition();
-
-        ListAdapter adapter = getAdapter();
-        if (adapter != null) {
-            final int count = adapter.getCount();
-            for (int i = 0; i < count; i++) {
-                if (adapter.isEnabled(i)) {
-                    itemCount++;
-                } else if (i <= currentItemIndex) {
-                    currentItemIndex--;
-                }
-            }
-        }
-
-        event.setItemCount(itemCount);
-        event.setCurrentItemIndex(currentItemIndex);
-    }
-
     /**
      * setSelectionAfterHeaderView set the selection to be the first list item
      * after the header views.
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 3ac4e80..767eaee 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -721,13 +721,18 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        info.setScrollable(true);
+        info.setScrollable(getScrollRange() > 0);
     }
 
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-        event.setScrollable(true);
+        final boolean scrollable = getScrollRange() > 0;
+        event.setScrollable(scrollable);
+        event.setScrollX(mScrollX);
+        event.setScrollY(mScrollY);
+        event.setMaxScrollX(mScrollX);
+        event.setMaxScrollY(getScrollRange());
     }
 
     private int getScrollRange() {