[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:
hangyu
2023-11-17 13:31:33 -08:00
committed by GitHub
parent e7e9a40053
commit cd4c07d7a2
3 changed files with 41 additions and 6 deletions

View File

@@ -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.
*

View File

@@ -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)

View File

@@ -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) {