From adaafb29801b939ab9a5ad348a338ecab4c03098 Mon Sep 17 00:00:00 2001 From: Phil Weaver Date: Thu, 19 May 2016 10:32:52 -0700 Subject: [PATCH] Fix a11y crash when window layer isn't unique. TalkBack is seeing crashes that I can only explain by our assumption that window layer is unique in all cases. TalkBack reports that it happens during animation, so I assume that the layer may repeat transiently. Reducing our dependence on this assumption by traversing the list of windows sorted by layer without assuming that the list has the same length as the list of unsorted windows. Also documenting the undefined behavior of SparseArray when indexing beyond its bounds. The undefined behavior itself is intentional for performance reasons. Bug: 28679528 Bug: 28815817 Change-Id: I0c9f90b0b458b4cde465f603ba204fe6691e5c2c --- core/java/android/util/SparseArray.java | 14 ++++++++++++++ .../view/accessibility/AccessibilityCache.java | 7 +++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index dc965edd7fada..34e6f04f04044 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -160,6 +160,9 @@ public class SparseArray implements Cloneable { /** * Removes the mapping at the specified index. + * + *

For indices outside of the range 0...size()-1, + * the behavior is undefined.

*/ public void removeAt(int index) { if (mValues[index] != DELETED) { @@ -173,6 +176,9 @@ public class SparseArray implements Cloneable { * * @param index Index to begin at * @param size Number of mappings to remove + * + *

For indices outside of the range 0...size()-1, + * the behavior is undefined.

*/ public void removeAtRange(int index, int size) { final int end = Math.min(mSize, index + size); @@ -262,6 +268,9 @@ public class SparseArray implements Cloneable { * be in ascending order, e.g., keyAt(0) will return the * smallest key and keyAt(size()-1) will return the largest * key.

+ * + *

For indices outside of the range 0...size()-1, + * the behavior is undefined.

*/ public int keyAt(int index) { if (mGarbage) { @@ -281,6 +290,9 @@ public class SparseArray implements Cloneable { * valueAt(0) will return the value associated with the * smallest key and valueAt(size()-1) will return the value * associated with the largest key.

+ * + *

For indices outside of the range 0...size()-1, + * the behavior is undefined.

*/ @SuppressWarnings("unchecked") public E valueAt(int index) { @@ -295,6 +307,8 @@ public class SparseArray implements Cloneable { * Given an index in the range 0...size()-1, sets a new * value for the indexth key-value mapping that this * SparseArray stores. + * + *

For indices outside of the range 0...size()-1, the behavior is undefined.

*/ public void setValueAt(int index, E value) { if (mGarbage) { diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java index 1da305f09f541..28e31c4c7aa83 100644 --- a/core/java/android/view/accessibility/AccessibilityCache.java +++ b/core/java/android/view/accessibility/AccessibilityCache.java @@ -221,8 +221,11 @@ final class AccessibilityCache { sortedWindows.put(window.getLayer(), window); } - List windows = new ArrayList<>(windowCount); - for (int i = windowCount - 1; i >= 0; i--) { + // It's possible in transient conditions for two windows to share the same + // layer, which results in sortedWindows being smaller than mWindowCache + final int sortedWindowCount = sortedWindows.size(); + List windows = new ArrayList<>(sortedWindowCount); + for (int i = sortedWindowCount - 1; i >= 0; i--) { AccessibilityWindowInfo window = sortedWindows.valueAt(i); windows.add(AccessibilityWindowInfo.obtain(window)); sortedWindows.removeAt(i);