diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index d8a32b5ffc829..3c9bbeab5d5da 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -34,8 +34,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Bridge between Android's OS accessibility system and Flutter's accessibility system. @@ -635,7 +633,8 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } // These are non-ops on older devices. Attempting to interact with the text will cause Talkback - // to read the contents of the text box instead. + // to read the + // contents of the text box instead. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { if (semanticsNode.hasAction(Action.SET_SELECTION)) { result.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); @@ -651,13 +650,6 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } } - // Set text API isn't available until API 21. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (semanticsNode.hasAction(Action.SET_TEXT)) { - result.addAction(AccessibilityNodeInfo.ACTION_SET_TEXT); - } - } - if (semanticsNode.hasFlag(Flag.IS_BUTTON) || semanticsNode.hasFlag(Flag.IS_LINK)) { result.setClassName("android.widget.Button"); } @@ -1042,12 +1034,6 @@ public boolean performAction( } accessibilityChannel.dispatchSemanticsAction( virtualViewId, Action.SET_SELECTION, selection); - // The voice access expects the semantics node to update immediately. We update the - // semantics node based on prediction. If the result is incorrect, it will be updated in - // the next frame. - SemanticsNode node = flutterSemanticsTree.get(virtualViewId); - node.textSelectionBase = selection.get("base"); - node.textSelectionExtent = selection.get("extent"); return true; } case AccessibilityNodeInfo.ACTION_COPY: @@ -1078,7 +1064,7 @@ public boolean performAction( if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return false; } - return performSetText(semanticsNode, virtualViewId, arguments); + return performSetText(virtualViewId, arguments); } default: // might be a custom accessibility accessibilityAction. @@ -1108,9 +1094,6 @@ private boolean performCursorMoveAction( arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); final boolean extendSelection = arguments.getBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); - // The voice access expects the semantics node to update immediately. We update the semantics - // node based on prediction. If the result is incorrect, it will be updated in the next frame. - predictCursorMovement(semanticsNode, granularity, forward, extendSelection); switch (granularity) { case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { @@ -1138,98 +1121,23 @@ private boolean performCursorMoveAction( return true; } break; - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE: - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE: - return true; } return false; } - private void predictCursorMovement( - @NonNull SemanticsNode node, int granularity, boolean forward, boolean extendSelection) { - if (node.textSelectionExtent < 0 || node.textSelectionBase < 0) { - return; - } - - switch (granularity) { - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: - if (forward && node.textSelectionExtent < node.value.length()) { - node.textSelectionExtent += 1; - } else if (!forward && node.textSelectionExtent > 0) { - node.textSelectionExtent -= 1; - } - break; - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: - if (forward && node.textSelectionExtent < node.value.length()) { - Pattern pattern = Pattern.compile("\\p{L}(\\b)"); - Matcher result = pattern.matcher(node.value.substring(node.textSelectionExtent)); - // we discard the first result because we want to find the "next" word - if (result.find() && result.find()) { - node.textSelectionExtent += result.start(1); - } else { - node.textSelectionExtent = node.value.length(); - } - } else if (!forward && node.textSelectionExtent > 0) { - // Finds last beginning of the word boundary. - Pattern pattern = Pattern.compile("(?s:.*)(\\b)\\p{L}"); - Matcher result = pattern.matcher(node.value.substring(0, node.textSelectionExtent)); - if (result.find()) { - node.textSelectionExtent = result.start(1); - } - } - break; - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE: - if (forward && node.textSelectionExtent < node.value.length()) { - // Finds the next new line. - Pattern pattern = Pattern.compile("(?!^)(\\n)"); - Matcher result = pattern.matcher(node.value.substring(node.textSelectionExtent)); - if (result.find()) { - node.textSelectionExtent += result.start(1); - } else { - node.textSelectionExtent = node.value.length(); - } - } else if (!forward && node.textSelectionExtent > 0) { - // Finds the last new line. - Pattern pattern = Pattern.compile("(?s:.*)(\\n)"); - Matcher result = pattern.matcher(node.value.substring(0, node.textSelectionExtent)); - if (result.find()) { - node.textSelectionExtent = result.start(1); - } else { - node.textSelectionExtent = 0; - } - } - break; - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: - case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE: - if (forward) { - node.textSelectionExtent = node.value.length(); - } else { - node.textSelectionExtent = 0; - } - break; - } - if (!extendSelection) { - node.textSelectionBase = node.textSelectionExtent; - } - } - /** * Handles the responsibilities of {@link #performAction(int, int, Bundle)} for the specific * scenario of cursor movement. */ @TargetApi(21) @RequiresApi(21) - private boolean performSetText(SemanticsNode node, int virtualViewId, @NonNull Bundle arguments) { + private boolean performSetText(int virtualViewId, @NonNull Bundle arguments) { String newText = ""; if (arguments != null && arguments.containsKey(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE)) { newText = arguments.getString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE); } accessibilityChannel.dispatchSemanticsAction(virtualViewId, Action.SET_TEXT, newText); - // The voice access expects the semantics node to update immediately. We update the semantics - // node based on prediction. If the result is incorrect, it will be updated in the next frame. - node.value = newText; return true; } diff --git a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index ca9c01d2c1509..7659f437d249d 100644 --- a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -6,7 +6,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; @@ -373,357 +372,6 @@ public void itCanPerformSetText() { .dispatchSemanticsAction(1, AccessibilityBridge.Action.SET_TEXT, expectedText); } - @TargetApi(21) - @Test - public void itCanPredictSetText() { - 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; - TestSemanticsNode node1 = new TestSemanticsNode(); - node1.id = 1; - node1.addFlag(AccessibilityBridge.Flag.IS_TEXT_FIELD); - root.children.add(node1); - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings); - Bundle bundle = new Bundle(); - String expectedText = "some string"; - bundle.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, expectedText); - accessibilityBridge.performAction(1, AccessibilityNodeInfo.ACTION_SET_TEXT, bundle); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - assertEquals(nodeInfo.getText(), expectedText); - } - - @TargetApi(21) - @Test - public void itCanCreateAccessibilityNodeInfoWithSetText() { - 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; - TestSemanticsNode node1 = new TestSemanticsNode(); - node1.id = 1; - node1.addFlag(AccessibilityBridge.Flag.IS_TEXT_FIELD); - node1.addAction(AccessibilityBridge.Action.SET_TEXT); - root.children.add(node1); - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - List actions = nodeInfo.getActionList(); - assertTrue(actions.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT)); - } - - @Test - public void itCanPredictSetSelection() { - 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; - TestSemanticsNode node1 = new TestSemanticsNode(); - node1.id = 1; - node1.value = "some text"; - node1.textSelectionBase = -1; - node1.textSelectionExtent = -1; - node1.addFlag(AccessibilityBridge.Flag.IS_TEXT_FIELD); - root.children.add(node1); - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings); - Bundle bundle = new Bundle(); - int expectedStart = 1; - int expectedEnd = 3; - bundle.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, expectedStart); - bundle.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, expectedEnd); - accessibilityBridge.performAction(1, AccessibilityNodeInfo.ACTION_SET_SELECTION, bundle); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - assertEquals(nodeInfo.getTextSelectionStart(), expectedStart); - assertEquals(nodeInfo.getTextSelectionEnd(), expectedEnd); - } - - @Test - public void itCanPredictCursorMovementsWithGranularityWord() { - 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; - TestSemanticsNode node1 = new TestSemanticsNode(); - node1.id = 1; - node1.value = "some text"; - node1.textSelectionBase = 0; - node1.textSelectionExtent = 0; - node1.addFlag(AccessibilityBridge.Flag.IS_TEXT_FIELD); - root.children.add(node1); - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings); - Bundle bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, bundle); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - // The seletction should be at the end of 'text' - assertEquals(nodeInfo.getTextSelectionStart(), 9); - assertEquals(nodeInfo.getTextSelectionEnd(), 9); - - bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, bundle); - nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - // The seletction should be go to beginning of 'text'. - assertEquals(nodeInfo.getTextSelectionStart(), 5); - assertEquals(nodeInfo.getTextSelectionEnd(), 5); - } - - @Test - public void itCanPredictCursorMovementsWithGranularityWordUnicode() { - 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; - TestSemanticsNode node1 = new TestSemanticsNode(); - node1.id = 1; - node1.value = "你 好 嗎"; - node1.textSelectionBase = 0; - node1.textSelectionExtent = 0; - node1.addFlag(AccessibilityBridge.Flag.IS_TEXT_FIELD); - root.children.add(node1); - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings); - Bundle bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, bundle); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - // The seletction should be at the end of '好' - assertEquals(nodeInfo.getTextSelectionStart(), 3); - assertEquals(nodeInfo.getTextSelectionEnd(), 3); - - bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, bundle); - nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - // The seletction should be go to beginning of '好'. - assertEquals(nodeInfo.getTextSelectionStart(), 2); - assertEquals(nodeInfo.getTextSelectionEnd(), 2); - } - - @Test - public void itCanPredictCursorMovementsWithGranularityLine() { - 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; - TestSemanticsNode node1 = new TestSemanticsNode(); - node1.id = 1; - node1.value = "How are you\nI am fine\nThank you"; - // Selection is at the second line. - node1.textSelectionBase = 14; - node1.textSelectionExtent = 14; - node1.addFlag(AccessibilityBridge.Flag.IS_TEXT_FIELD); - root.children.add(node1); - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings); - Bundle bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, bundle); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - // The seletction should be at the beginning of the third line. - assertEquals(nodeInfo.getTextSelectionStart(), 21); - assertEquals(nodeInfo.getTextSelectionEnd(), 21); - - bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, bundle); - nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - // The seletction should be at the beginning of the second line. - assertEquals(nodeInfo.getTextSelectionStart(), 11); - assertEquals(nodeInfo.getTextSelectionEnd(), 11); - } - - @Test - public void itCanPredictCursorMovementsWithGranularityCharacter() { - 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; - TestSemanticsNode node1 = new TestSemanticsNode(); - node1.id = 1; - node1.value = "some text"; - node1.textSelectionBase = 0; - node1.textSelectionExtent = 0; - node1.addFlag(AccessibilityBridge.Flag.IS_TEXT_FIELD); - root.children.add(node1); - TestSemanticsUpdate testSemanticsUpdate = root.toUpdate(); - accessibilityBridge.updateSemantics(testSemanticsUpdate.buffer, testSemanticsUpdate.strings); - Bundle bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, bundle); - AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - assertEquals(nodeInfo.getTextSelectionStart(), 1); - assertEquals(nodeInfo.getTextSelectionEnd(), 1); - - bundle = new Bundle(); - bundle.putInt( - AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, - AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); - bundle.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); - accessibilityBridge.performAction( - 1, AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, bundle); - nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(1); - assertEquals(nodeInfo.getTextSelectionStart(), 0); - assertEquals(nodeInfo.getTextSelectionEnd(), 0); - } - @Test public void itAnnouncesWhiteSpaceWhenNoNamesRoute() { AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); @@ -952,10 +600,6 @@ void addFlag(AccessibilityBridge.Flag flag) { flags |= flag.value; } - void addAction(AccessibilityBridge.Action action) { - actions |= action.value; - } - // These fields are declared in the order they should be // encoded. int id = 0;