From f4f5f5c239022189a7ee7b1be9b42385e5e68e96 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 13 Aug 2021 21:21:00 -0700 Subject: [PATCH] Revert "Sets focus before sending a11y focus event in Android (#27992)" This reverts commit 56cf8198a773d9d1c7b7febe7988252af852a229. --- .../io/flutter/view/AccessibilityBridge.java | 17 +-- .../flutter/view/AccessibilityBridgeTest.java | 118 ------------------ 2 files changed, 6 insertions(+), 129 deletions(-) diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 6728cde166fec..308e1de10be78 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -1020,33 +1020,28 @@ public boolean performAction( } case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { - // Focused semantics node must be reset before sending the - // TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED event. Otherwise, - // TalkBack may think the node is still focused. - accessibilityFocusedSemanticsNode = null; - embeddedAccessibilityFocusedNodeId = null; accessibilityChannel.dispatchSemanticsAction( virtualViewId, Action.DID_LOSE_ACCESSIBILITY_FOCUS); sendAccessibilityEvent( virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + accessibilityFocusedSemanticsNode = null; + embeddedAccessibilityFocusedNodeId = null; return true; } case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { + accessibilityChannel.dispatchSemanticsAction( + virtualViewId, Action.DID_GAIN_ACCESSIBILITY_FOCUS); + sendAccessibilityEvent(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); + if (accessibilityFocusedSemanticsNode == null) { // When Android focuses a node, it doesn't invalidate the view. // (It does when it sends ACTION_CLEAR_ACCESSIBILITY_FOCUS, so // we only have to worry about this when the focused node is null.) rootAccessibilityView.invalidate(); } - // Focused semantics node must be set before sending the TYPE_VIEW_ACCESSIBILITY_FOCUSED - // event. Otherwise, TalkBack may think the node is not focused yet. accessibilityFocusedSemanticsNode = semanticsNode; - accessibilityChannel.dispatchSemanticsAction( - virtualViewId, Action.DID_GAIN_ACCESSIBILITY_FOCUS); - sendAccessibilityEvent(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); - if (semanticsNode.hasAction(Action.INCREASE) || semanticsNode.hasAction(Action.DECREASE)) { // SeekBars only announce themselves after this event. diff --git a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index 1fc72c21fa5e5..1bb45d8592a72 100644 --- a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -5,7 +5,6 @@ package io.flutter.view; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.eq; @@ -47,7 +46,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -800,122 +798,6 @@ public void itCanPredictSetSelection() { assertEquals(nodeInfo.getTextSelectionEnd(), expectedEnd); } - @Test - public void itSetsFocusedNodeBeforeSendingEvent() { - AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); - 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( - /*rootAccessibilityView=*/ mockRootView, - /*accessibilityChannel=*/ mockChannel, - /*accessibilityManager=*/ mockManager, - /*contentResolver=*/ null, - /*accessibilityViewEmbedder=*/ mockViewEmbedder, - /*platformViewsAccessibilityDelegate=*/ null); - - ViewParent mockParent = mock(ViewParent.class); - when(mockRootView.getParent()).thenReturn(mockParent); - when(mockManager.isEnabled()).thenReturn(true); - - TestSemanticsNode root = new TestSemanticsNode(); - root.id = 0; - root.label = "root"; - - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - testSemanticsUpdate.sendUpdateToBridge(accessibilityBridge); - - class Verifier { - public Verifier(AccessibilityBridge accessibilityBridge) { - this.accessibilityBridge = accessibilityBridge; - } - - public AccessibilityBridge accessibilityBridge; - public boolean verified = false; - - public boolean verify(InvocationOnMock invocation) { - AccessibilityEvent event = (AccessibilityEvent) invocation.getArguments()[1]; - assertEquals(event.getEventType(), AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); - // The accessibility focus must be set before sending out - // the TYPE_VIEW_ACCESSIBILITY_FOCUSED event. - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0); - assertTrue(nodeInfo.isAccessibilityFocused()); - verified = true; - return true; - } - }; - Verifier verifier = new Verifier(accessibilityBridge); - when(mockParent.requestSendAccessibilityEvent(eq(mockRootView), any(AccessibilityEvent.class))) - .thenAnswer(invocation -> verifier.verify(invocation)); - accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - assertTrue(verifier.verified); - } - - @Test - public void itClearsFocusedNodeBeforeSendingEvent() { - AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); - 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( - /*rootAccessibilityView=*/ mockRootView, - /*accessibilityChannel=*/ mockChannel, - /*accessibilityManager=*/ mockManager, - /*contentResolver=*/ null, - /*accessibilityViewEmbedder=*/ mockViewEmbedder, - /*platformViewsAccessibilityDelegate=*/ null); - - ViewParent mockParent = mock(ViewParent.class); - when(mockRootView.getParent()).thenReturn(mockParent); - when(mockManager.isEnabled()).thenReturn(true); - - TestSemanticsNode root = new TestSemanticsNode(); - root.id = 0; - root.label = "root"; - - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - testSemanticsUpdate.sendUpdateToBridge(accessibilityBridge); - // Set the focus on root. - accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0); - assertTrue(nodeInfo.isAccessibilityFocused()); - - class Verifier { - public Verifier(AccessibilityBridge accessibilityBridge) { - this.accessibilityBridge = accessibilityBridge; - } - - public AccessibilityBridge accessibilityBridge; - public boolean verified = false; - - public boolean verify(InvocationOnMock invocation) { - AccessibilityEvent event = (AccessibilityEvent) invocation.getArguments()[1]; - assertEquals( - event.getEventType(), AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); - // The accessibility focus must be cleared before sending out - // the TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED event. - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0); - assertFalse(nodeInfo.isAccessibilityFocused()); - verified = true; - return true; - } - }; - Verifier verifier = new Verifier(accessibilityBridge); - when(mockParent.requestSendAccessibilityEvent(eq(mockRootView), any(AccessibilityEvent.class))) - .thenAnswer(invocation -> verifier.verify(invocation)); - accessibilityBridge.performAction( - 0, AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); - assertTrue(verifier.verified); - } - @Test public void itCanPredictCursorMovementsWithGranularityWord() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class);