Missing default focus when navigating to a page with no SemanticsNode that sets namesRoute:true (#20516)

This commit is contained in:
chunhtai 2020-08-19 14:06:03 -07:00 committed by GitHub
parent 3930ac1b25
commit ccaee70b05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 0 deletions

View File

@ -1548,6 +1548,17 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
AccessibilityEvent event =
obtainAccessibilityEvent(route.id, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
String routeName = route.getRouteName();
if (routeName == null) {
// The routeName will be null when there is no semantics node that represnets namesRoute in
// the scopeRoute. The TYPE_WINDOW_STATE_CHANGED only works the route name is not null and not
// empty. Gives it a whitespace will make it focus the first semantics node without
// pronouncing any word.
//
// The other way to trigger a focus change is to send a TYPE_VIEW_FOCUSED to the
// rootAccessibilityView. However, it is less predictable which semantics node it will focus
// next.
routeName = " ";
}
event.getText().add(routeName);
sendAccessibilityEvent(event);
}

View File

@ -132,6 +132,41 @@ public class AccessibilityBridgeTest {
assertEquals(event.getEventType(), AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
}
@Test
public void itAnnouncesWhiteSpaceWhenNoNamesRoute() {
AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class);
AccessibilityManager mockManager = mock(AccessibilityManager.class);
View mockRootView = mock(View.class);
Context context = mock(Context.class);
when(mockRootView.getContext()).thenReturn(context);
when(context.getPackageName()).thenReturn("test");
AccessibilityBridge accessibilityBridge =
setUpBridge(mockRootView, mockManager, mockViewEmbedder);
ViewParent mockParent = mock(ViewParent.class);
when(mockRootView.getParent()).thenReturn(mockParent);
when(mockManager.isEnabled()).thenReturn(true);
// Sent a11y tree with scopeRoute without namesRoute.
TestSemanticsNode root = new TestSemanticsNode();
root.id = 0;
TestSemanticsNode scopeRoute = new TestSemanticsNode();
scopeRoute.id = 1;
scopeRoute.addFlag(AccessibilityBridge.Flag.SCOPES_ROUTE);
root.children.add(scopeRoute);
TestSemanticsUpdate testSemanticsUpdate = root.toUpdate();
accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings);
ArgumentCaptor<AccessibilityEvent> eventCaptor =
ArgumentCaptor.forClass(AccessibilityEvent.class);
verify(mockParent, times(2))
.requestSendAccessibilityEvent(eq(mockRootView), eventCaptor.capture());
AccessibilityEvent event = eventCaptor.getAllValues().get(0);
assertEquals(event.getEventType(), AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
List<CharSequence> sentences = event.getText();
assertEquals(sentences.size(), 1);
assertEquals(sentences.get(0).toString(), " ");
}
@Test
public void itHoverOverOutOfBoundsDoesNotCrash() {
// SementicsNode.hitTest() returns null when out of bounds.