diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java index 38059232ce1a7..f2d12b181af25 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java @@ -2,6 +2,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import io.flutter.Log; import io.flutter.embedding.engine.FlutterJNI; import io.flutter.embedding.engine.dart.DartExecutor; @@ -102,6 +103,13 @@ public AccessibilityChannel(@NonNull DartExecutor dartExecutor, @NonNull Flutter this.flutterJNI = flutterJNI; } + @VisibleForTesting + public AccessibilityChannel( + @NonNull BasicMessageChannel channel, @NonNull FlutterJNI flutterJNI) { + this.channel = channel; + this.flutterJNI = flutterJNI; + } + /** * Informs Flutter that the Android OS currently has accessibility enabled. * diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index c7c249713fff8..8f2584cb745c2 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -1166,6 +1166,12 @@ public boolean performAction( accessibilityChannel.dispatchSemanticsAction( virtualViewId, Action.DID_GAIN_ACCESSIBILITY_FOCUS); + + HashMap message = new HashMap<>(); + message.put("type", "didGainFocus"); + message.put("nodeId", semanticsNode.id); + accessibilityChannel.channel.send(message); + sendAccessibilityEvent(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); if (semanticsNode.hasAction(Action.INCREASE) diff --git a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index 28077a2c6877e..12054c9638b5c 100644 --- a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -1187,7 +1187,9 @@ public void itCanPredictSetSelection() { @Test public void itPerformsClearAccessibilityFocusCorrectly() { - AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); + BasicMessageChannel mockChannel = mock(BasicMessageChannel.class); + AccessibilityChannel accessibilityChannel = + new AccessibilityChannel(mockChannel, mock(FlutterJNI.class)); AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); AccessibilityManager mockManager = mock(AccessibilityManager.class); View mockRootView = mock(View.class); @@ -1197,7 +1199,7 @@ public void itPerformsClearAccessibilityFocusCorrectly() { AccessibilityBridge accessibilityBridge = setUpBridge( /*rootAccessibilityView=*/ mockRootView, - /*accessibilityChannel=*/ mockChannel, + /*accessibilityChannel=*/ accessibilityChannel, /*accessibilityManager=*/ mockManager, /*contentResolver=*/ null, /*accessibilityViewEmbedder=*/ mockViewEmbedder, @@ -1220,6 +1222,11 @@ public void itPerformsClearAccessibilityFocusCorrectly() { accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0); assertTrue(nodeInfo.isAccessibilityFocused()); + + HashMap message = new HashMap<>(); + message.put("type", "didGainFocus"); + message.put("nodeId", 0); + verify(mockChannel).send(message); // Clear focus on non-focused node shouldn't do anything accessibilityBridge.performAction( 1, AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); @@ -1310,7 +1317,10 @@ public void itSetsBoldTextFlagCorrectly() { @Test public void itSetsFocusedNodeBeforeSendingEvent() { - AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); + BasicMessageChannel mockChannel = mock(BasicMessageChannel.class); + AccessibilityChannel accessibilityChannel = + new AccessibilityChannel(mockChannel, mock(FlutterJNI.class)); + AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); AccessibilityManager mockManager = mock(AccessibilityManager.class); View mockRootView = mock(View.class); @@ -1320,7 +1330,7 @@ public void itSetsFocusedNodeBeforeSendingEvent() { AccessibilityBridge accessibilityBridge = setUpBridge( /*rootAccessibilityView=*/ mockRootView, - /*accessibilityChannel=*/ mockChannel, + /*accessibilityChannel=*/ accessibilityChannel, /*accessibilityManager=*/ mockManager, /*contentResolver=*/ null, /*accessibilityViewEmbedder=*/ mockViewEmbedder, @@ -1361,11 +1371,18 @@ public boolean verify(InvocationOnMock invocation) { .thenAnswer(invocation -> verifier.verify(invocation)); accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); assertTrue(verifier.verified); + + HashMap message = new HashMap<>(); + message.put("type", "didGainFocus"); + message.put("nodeId", 0); + verify(mockChannel).send(message); } @Test public void itClearsFocusedNodeBeforeSendingEvent() { - AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); + BasicMessageChannel mockChannel = mock(BasicMessageChannel.class); + AccessibilityChannel accessibilityChannel = + new AccessibilityChannel(mockChannel, mock(FlutterJNI.class)); AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); AccessibilityManager mockManager = mock(AccessibilityManager.class); View mockRootView = mock(View.class); @@ -1375,7 +1392,7 @@ public void itClearsFocusedNodeBeforeSendingEvent() { AccessibilityBridge accessibilityBridge = setUpBridge( /*rootAccessibilityView=*/ mockRootView, - /*accessibilityChannel=*/ mockChannel, + /*accessibilityChannel=*/ accessibilityChannel, /*accessibilityManager=*/ mockManager, /*contentResolver=*/ null, /*accessibilityViewEmbedder=*/ mockViewEmbedder, @@ -1395,6 +1412,10 @@ public void itClearsFocusedNodeBeforeSendingEvent() { accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0); assertTrue(nodeInfo.isAccessibilityFocused()); + HashMap message = new HashMap<>(); + message.put("type", "didGainFocus"); + message.put("nodeId", 0); + verify(mockChannel).send(message); class Verifier { public Verifier(AccessibilityBridge accessibilityBridge) {