Fix: add Android accessibility bounds offset when FlutterView's location is not left top corner (flutter/engine#25670)

This commit is contained in:
eggfly 2021-04-21 00:37:25 +08:00 committed by GitHub
parent 8e02ee474a
commit bddb13004d
2 changed files with 52 additions and 1 deletions

View File

@ -693,7 +693,8 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
} else {
result.setBoundsInParent(bounds);
}
result.setBoundsInScreen(bounds);
final Rect boundsInScreen = getBoundsInScreen(bounds);
result.setBoundsInScreen(boundsInScreen);
result.setVisibleToUser(true);
result.setEnabled(
!semanticsNode.hasFlag(Flag.HAS_ENABLED_STATE) || semanticsNode.hasFlag(Flag.IS_ENABLED));
@ -869,6 +870,20 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
return result;
}
/**
* Get the bounds in screen with root FlutterView's offset.
*
* @param bounds the bounds in FlutterView
* @return the bounds with offset
*/
private Rect getBoundsInScreen(Rect bounds) {
Rect boundsInScreen = new Rect(bounds);
int[] locationOnScreen = new int[2];
rootAccessibilityView.getLocationOnScreen(locationOnScreen);
boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
return boundsInScreen;
}
/**
* Instructs the view represented by {@code virtualViewId} to carry out the desired {@code
* accessibilityAction}, perhaps configured by additional {@code arguments}.

View File

@ -10,6 +10,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@ -76,6 +77,41 @@ public class AccessibilityBridgeTest {
assertEquals(nodeInfo.getText(), "Hello, World");
}
@Test
public void itTakesGlobalCoordinatesOfFlutterViewIntoAccount() {
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);
final int position = 88;
// The getBoundsInScreen() in createAccessibilityNodeInfo() needs View.getLocationOnScreen()
doAnswer(
invocation -> {
int[] outLocation = (int[]) invocation.getArguments()[0];
outLocation[0] = position;
outLocation[1] = position;
return null;
})
.when(mockRootView)
.getLocationOnScreen(any(int[].class));
when(context.getPackageName()).thenReturn("test");
AccessibilityBridge accessibilityBridge =
setUpBridge(mockRootView, mockManager, mockViewEmbedder);
TestSemanticsNode testSemanticsNode = new TestSemanticsNode();
TestSemanticsUpdate testSemanticsUpdate = testSemanticsNode.toUpdate();
accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings);
AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0);
Rect outBoundsInScreen = new Rect();
nodeInfo.getBoundsInScreen(outBoundsInScreen);
assertEquals(position, outBoundsInScreen.left);
assertEquals(position, outBoundsInScreen.top);
}
@Test
public void itDoesNotContainADescriptionIfScopesRoute() {
AccessibilityBridge accessibilityBridge = setUpBridge();