From ec66fb8f99b80a775a6796439e9fb5ec071e1153 Mon Sep 17 00:00:00 2001 From: Phil Weaver Date: Thu, 23 Mar 2017 12:21:53 -0700 Subject: [PATCH] Fix problem with ListView accessibility focus A scrap view was retaining accessibility focus, leading to a confusing experience for screen reader users. Part of the problem is that views can change even when the adapter has stable ids. This change tightens the condition for restoring a11y focus to the same view. AbsListView also allowed scrap views to maintain a11y focus. While this may make sense if the views will be reused, it is wrong if the views are not reused. Bug: 29403113 Test: Verified that a11y focus stays put when toggling the preference: Settings -> System -> Language & input -> Virtual keyboards -> Advanced -> Symbol for physical keyboard Change-Id: Ie4a15027088f158d9ed4bb3f3eeff5a288c25832 (cherry picked from commit ab4717aa2a7d0e19f4b08b2c851a541f9b0c9c6b) --- core/java/android/widget/AbsListView.java | 8 +++++--- core/java/android/widget/ListView.java | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 1937187defed9..99b91bdf046b7 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -6873,9 +6873,11 @@ public abstract class AbsListView extends AdapterView implements Te mTransientStateViews.put(position, scrap); } else { // Otherwise, we'll have to remove the view and start over. + clearScrapForRebind(scrap); getSkippedScrap().add(scrap); } } else { + clearScrapForRebind(scrap); if (mViewTypeCount == 1) { mCurrentScrap.add(scrap); } else { @@ -7098,12 +7100,12 @@ public abstract class AbsListView extends AdapterView implements Te } } else if (params.scrappedFromPosition == position) { final View scrap = scrapViews.remove(i); - clearAccessibilityFromScrap(scrap); + clearScrapForRebind(scrap); return scrap; } } final View scrap = scrapViews.remove(size - 1); - clearAccessibilityFromScrap(scrap); + clearScrapForRebind(scrap); return scrap; } else { return null; @@ -7117,7 +7119,7 @@ public abstract class AbsListView extends AdapterView implements Te } } - private void clearAccessibilityFromScrap(View view) { + private void clearScrapForRebind(View view) { view.clearAccessibilityFocus(); view.setAccessibilityDelegate(null); } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 1c0c4ef7cba73..12e35a14e3814 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1639,7 +1639,7 @@ public class ListView extends AbsListView { final View focusChild = getAccessibilityFocusedChild(focusHost); if (focusChild != null) { if (!dataChanged || isDirectChildHeaderOrFooter(focusChild) - || focusChild.hasTransientState() || mAdapterHasStableIds) { + || (focusChild.hasTransientState() && mAdapterHasStableIds)) { // The views won't be changing, so try to maintain // focus on the current host and virtual view. accessibilityFocusLayoutRestoreView = focusHost;