Fix the a11y focus problem in a long list page
While a page is scrolling to the target position, the target can't request a11y focus, and the highlight blink animation at the moment is also invisible. The patch is to skip the unseen highlight animation and focus operation when onBindViewHolder() is called before scrolling. Therefore, when the scrolling stops, the scroll listener will notify the item changed and onBindViewHolder() will be called again to do the operations. Also decrease the delay time of the scrolling start to make the a11y smoother. Bug: 318459003 Test: manual, robotest Change-Id: Ie55b2edeb7e1feaaadb5e670f39f07f6f17b92b9
This commit is contained in:
@@ -33,6 +33,7 @@ import android.content.Context;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
@@ -54,6 +55,8 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowAccessibilityManager;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@@ -67,7 +70,7 @@ public class HighlightablePreferenceGroupAdapterTest {
|
||||
@Mock
|
||||
private View mRoot;
|
||||
@Mock
|
||||
private PreferenceCategory mPreferenceCatetory;
|
||||
private PreferenceCategory mPreferenceCategory;
|
||||
@Mock
|
||||
private SettingsPreferenceFragment mFragment;
|
||||
|
||||
@@ -82,8 +85,8 @@ public class HighlightablePreferenceGroupAdapterTest {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPreference = new Preference(mContext);
|
||||
mPreference.setKey(TEST_KEY);
|
||||
when(mPreferenceCatetory.getContext()).thenReturn(mContext);
|
||||
mAdapter = spy(new HighlightablePreferenceGroupAdapter(mPreferenceCatetory, TEST_KEY,
|
||||
when(mPreferenceCategory.getContext()).thenReturn(mContext);
|
||||
mAdapter = spy(new HighlightablePreferenceGroupAdapter(mPreferenceCategory, TEST_KEY,
|
||||
false /* highlighted*/));
|
||||
when(mAdapter.getItem(anyInt())).thenReturn(mPreference);
|
||||
mViewHolder = PreferenceViewHolder.createInstanceForTests(
|
||||
@@ -101,6 +104,18 @@ public class HighlightablePreferenceGroupAdapterTest {
|
||||
eq(HighlightablePreferenceGroupAdapter.DELAY_HIGHLIGHT_DURATION_MILLIS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestHighlight_enableTouchExploration_shouldHaveA11yHighlightDelay() {
|
||||
ShadowAccessibilityManager am = Shadow.extract(AccessibilityManager.getInstance(mContext));
|
||||
am.setTouchExplorationEnabled(true);
|
||||
when(mAdapter.getPreferenceAdapterPosition(anyString())).thenReturn(1);
|
||||
mAdapter.requestHighlight(mRoot, mock(RecyclerView.class), mock(AppBarLayout.class));
|
||||
|
||||
// DELAY_HIGHLIGHT_DURATION_MILLIS_A11Y = DELAY_COLLAPSE_DURATION_MILLIS
|
||||
verify(mRoot, times(2)).postDelayed(any(),
|
||||
eq(HighlightablePreferenceGroupAdapter.DELAY_HIGHLIGHT_DURATION_MILLIS_A11Y));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestHighlight_noKey_highlightedBefore_noRecyclerView_shouldNotRequest() {
|
||||
ReflectionHelpers.setField(mAdapter, "mHighlightKey", null);
|
||||
@@ -178,12 +193,24 @@ public class HighlightablePreferenceGroupAdapterTest {
|
||||
assertThat(mViewHolder.itemView.getTag(R.id.preference_highlighted)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBackground_itemViewIsInvisible_shouldNotSetHighlightedTag() {
|
||||
ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10);
|
||||
ReflectionHelpers.setField(mViewHolder, "itemView", spy(mViewHolder.itemView));
|
||||
when(mViewHolder.itemView.isShown()).thenReturn(false);
|
||||
|
||||
mAdapter.updateBackground(mViewHolder, 0);
|
||||
|
||||
assertThat(mViewHolder.itemView.getTag(R.id.preference_highlighted)).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* When background is being updated, we also request the a11y focus on the preference
|
||||
*/
|
||||
@Test
|
||||
public void updateBackground_shouldRequestAccessibilityFocus() {
|
||||
View viewItem = mock(View.class);
|
||||
when(viewItem.isShown()).thenReturn(true);
|
||||
mViewHolder = PreferenceViewHolder.createInstanceForTests(viewItem);
|
||||
ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10);
|
||||
|
||||
@@ -195,6 +222,8 @@ public class HighlightablePreferenceGroupAdapterTest {
|
||||
@Test
|
||||
public void updateBackground_highlight_shouldAnimateBackgroundAndSetHighlightedTag() {
|
||||
ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10);
|
||||
ReflectionHelpers.setField(mViewHolder, "itemView", spy(mViewHolder.itemView));
|
||||
when(mViewHolder.itemView.isShown()).thenReturn(true);
|
||||
assertThat(mAdapter.mFadeInAnimated).isFalse();
|
||||
|
||||
mAdapter.updateBackground(mViewHolder, 10);
|
||||
@@ -205,10 +234,22 @@ public class HighlightablePreferenceGroupAdapterTest {
|
||||
verify(mAdapter).requestRemoveHighlightDelayed(mViewHolder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBackground_highlight_itemViewIsInvisible_shouldNotAnimate() {
|
||||
ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10);
|
||||
ReflectionHelpers.setField(mViewHolder, "itemView", spy(mViewHolder.itemView));
|
||||
when(mViewHolder.itemView.isShown()).thenReturn(false);
|
||||
|
||||
mAdapter.updateBackground(mViewHolder, 10);
|
||||
|
||||
assertThat(mAdapter.mFadeInAnimated).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBackgroundTwice_highlight_shouldAnimateOnce() {
|
||||
ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10);
|
||||
ReflectionHelpers.setField(mViewHolder, "itemView", spy(mViewHolder.itemView));
|
||||
when(mViewHolder.itemView.isShown()).thenReturn(true);
|
||||
assertThat(mAdapter.mFadeInAnimated).isFalse();
|
||||
mAdapter.updateBackground(mViewHolder, 10);
|
||||
// mFadeInAnimated change from false to true - indicating background change is scheduled
|
||||
|
Reference in New Issue
Block a user