[Android] Send " did gain focus" message from engine to framework (flutter/engine#47114)
issue:https://github.com/flutter/flutter/issues/97747 framework pr:https://github.com/flutter/flutter/pull/135771 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I signed the [CLA]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Reid Baker <reidbaker@google.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package io.flutter.embedding.engine.systemchannels;
|
||||
|
||||
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 class AccessibilityChannel {
|
||||
this.flutterJNI = flutterJNI;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public AccessibilityChannel(
|
||||
@NonNull BasicMessageChannel<Object> channel, @NonNull FlutterJNI flutterJNI) {
|
||||
this.channel = channel;
|
||||
this.flutterJNI = flutterJNI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs Flutter that the Android OS currently has accessibility enabled.
|
||||
*
|
||||
|
||||
@@ -1166,6 +1166,12 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
|
||||
|
||||
accessibilityChannel.dispatchSemanticsAction(
|
||||
virtualViewId, Action.DID_GAIN_ACCESSIBILITY_FOCUS);
|
||||
|
||||
HashMap<String, Object> 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)
|
||||
|
||||
@@ -1187,7 +1187,9 @@ public class AccessibilityBridgeTest {
|
||||
|
||||
@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 class AccessibilityBridgeTest {
|
||||
AccessibilityBridge accessibilityBridge =
|
||||
setUpBridge(
|
||||
/*rootAccessibilityView=*/ mockRootView,
|
||||
/*accessibilityChannel=*/ mockChannel,
|
||||
/*accessibilityChannel=*/ accessibilityChannel,
|
||||
/*accessibilityManager=*/ mockManager,
|
||||
/*contentResolver=*/ null,
|
||||
/*accessibilityViewEmbedder=*/ mockViewEmbedder,
|
||||
@@ -1220,6 +1222,11 @@ public class AccessibilityBridgeTest {
|
||||
accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
|
||||
AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0);
|
||||
assertTrue(nodeInfo.isAccessibilityFocused());
|
||||
|
||||
HashMap<String, Object> 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 class AccessibilityBridgeTest {
|
||||
|
||||
@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 class AccessibilityBridgeTest {
|
||||
AccessibilityBridge accessibilityBridge =
|
||||
setUpBridge(
|
||||
/*rootAccessibilityView=*/ mockRootView,
|
||||
/*accessibilityChannel=*/ mockChannel,
|
||||
/*accessibilityChannel=*/ accessibilityChannel,
|
||||
/*accessibilityManager=*/ mockManager,
|
||||
/*contentResolver=*/ null,
|
||||
/*accessibilityViewEmbedder=*/ mockViewEmbedder,
|
||||
@@ -1361,11 +1371,18 @@ public class AccessibilityBridgeTest {
|
||||
.thenAnswer(invocation -> verifier.verify(invocation));
|
||||
accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
|
||||
assertTrue(verifier.verified);
|
||||
|
||||
HashMap<String, Object> 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 class AccessibilityBridgeTest {
|
||||
AccessibilityBridge accessibilityBridge =
|
||||
setUpBridge(
|
||||
/*rootAccessibilityView=*/ mockRootView,
|
||||
/*accessibilityChannel=*/ mockChannel,
|
||||
/*accessibilityChannel=*/ accessibilityChannel,
|
||||
/*accessibilityManager=*/ mockManager,
|
||||
/*contentResolver=*/ null,
|
||||
/*accessibilityViewEmbedder=*/ mockViewEmbedder,
|
||||
@@ -1395,6 +1412,10 @@ public class AccessibilityBridgeTest {
|
||||
accessibilityBridge.performAction(0, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
|
||||
AccessibilityNodeInfo nodeInfo = accessibilityBridge.createAccessibilityNodeInfo(0);
|
||||
assertTrue(nodeInfo.isAccessibilityFocused());
|
||||
HashMap<String, Object> message = new HashMap<>();
|
||||
message.put("type", "didGainFocus");
|
||||
message.put("nodeId", 0);
|
||||
verify(mockChannel).send(message);
|
||||
|
||||
class Verifier {
|
||||
public Verifier(AccessibilityBridge accessibilityBridge) {
|
||||
|
||||
Reference in New Issue
Block a user