Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
AccessibilityChannel.java
Go to the documentation of this file.
1package io.flutter.embedding.engine.systemchannels;
2
3import androidx.annotation.NonNull;
4import androidx.annotation.Nullable;
5import androidx.annotation.VisibleForTesting;
6import io.flutter.Log;
7import io.flutter.embedding.engine.FlutterJNI;
8import io.flutter.embedding.engine.dart.DartExecutor;
9import io.flutter.plugin.common.BasicMessageChannel;
10import io.flutter.plugin.common.StandardMessageCodec;
11import io.flutter.view.AccessibilityBridge;
12import java.util.HashMap;
13
14/**
15 * System channel that sends accessibility requests and events from Flutter to Android.
16 *
17 * <p>See {@link AccessibilityMessageHandler}, which lists all accessibility requests and events
18 * that might be sent from Flutter to the Android platform.
19 */
21 private static final String TAG = "AccessibilityChannel";
22
23 @NonNull public final BasicMessageChannel<Object> channel;
24 @NonNull public final FlutterJNI flutterJNI;
25 @Nullable private AccessibilityMessageHandler handler;
26
27 public final BasicMessageChannel.MessageHandler<Object> parsingMessageHandler =
28 new BasicMessageChannel.MessageHandler<Object>() {
29 @Override
30 public void onMessage(
31 @Nullable Object message, @NonNull BasicMessageChannel.Reply<Object> reply) {
32 // If there is no handler to respond to this message then we don't need to
33 // parse it. Return.
34 if (handler == null) {
35 reply.reply(null);
36 return;
37 }
38
39 @SuppressWarnings("unchecked")
40 final HashMap<String, Object> annotatedEvent = (HashMap<String, Object>) message;
41 final String type = (String) annotatedEvent.get("type");
42 @SuppressWarnings("unchecked")
43 final HashMap<String, Object> data = (HashMap<String, Object>) annotatedEvent.get("data");
44
45 Log.v(TAG, "Received " + type + " message.");
46 switch (type) {
47 case "announce":
48 String announceMessage = (String) data.get("message");
49 if (announceMessage != null) {
50 handler.announce(announceMessage);
51 }
52 break;
53 case "tap":
54 {
55 Integer nodeId = (Integer) annotatedEvent.get("nodeId");
56 if (nodeId != null) {
57 handler.onTap(nodeId);
58 }
59 break;
60 }
61 case "longPress":
62 {
63 Integer nodeId = (Integer) annotatedEvent.get("nodeId");
64 if (nodeId != null) {
65 handler.onLongPress(nodeId);
66 }
67 break;
68 }
69 case "focus":
70 {
71 Integer nodeId = (Integer) annotatedEvent.get("nodeId");
72 if (nodeId != null) {
73 handler.onFocus(nodeId);
74 }
75 break;
76 }
77 case "tooltip":
78 {
79 String tooltipMessage = (String) data.get("message");
80 if (tooltipMessage != null) {
81 handler.onTooltip(tooltipMessage);
82 }
83 break;
84 }
85 }
86 reply.reply(null);
87 }
88 };
89
90 /**
91 * Constructs an {@code AccessibilityChannel} that connects Android to the Dart code running in
92 * {@code dartExecutor}.
93 *
94 * <p>The given {@code dartExecutor} is permitted to be idle or executing code.
95 *
96 * <p>See {@link DartExecutor}.
97 */
98 public AccessibilityChannel(@NonNull DartExecutor dartExecutor, @NonNull FlutterJNI flutterJNI) {
99 channel =
100 new BasicMessageChannel<>(
101 dartExecutor, "flutter/accessibility", StandardMessageCodec.INSTANCE);
102 channel.setMessageHandler(parsingMessageHandler);
103 this.flutterJNI = flutterJNI;
104 }
105
106 @VisibleForTesting
108 @NonNull BasicMessageChannel<Object> channel, @NonNull FlutterJNI flutterJNI) {
109 this.channel = channel;
110 this.flutterJNI = flutterJNI;
111 }
112
113 /**
114 * Informs Flutter that the Android OS currently has accessibility enabled.
115 *
116 * <p>To accommodate enabled accessibility, this method instructs Flutter to activate its
117 * semantics tree, which forms the basis of Flutter's accessibility support.
118 */
122
123 /**
124 * Informs Flutter that the Android OS currently has accessibility disabled.
125 *
126 * <p>Given that accessibility is not required at this time, this method instructs Flutter to
127 * deactivate its semantics tree.
128 */
132
133 /**
134 * Instructs Flutter to activate/deactivate accessibility features corresponding to the flags
135 * provided by {@code accessibilityFeatureFlags}.
136 */
137 public void setAccessibilityFeatures(int accessibilityFeatureFlags) {
138 flutterJNI.setAccessibilityFeatures(accessibilityFeatureFlags);
139 }
140
141 /**
142 * Instructs Flutter to perform the given {@code action} on the {@code SemanticsNode} referenced
143 * by the given {@code virtualViewId}.
144 *
145 * <p>One might wonder why Flutter would need to be instructed that the user wants to perform an
146 * action. When the user is touching the screen in accessibility mode, Android takes over the
147 * touch input, categorizing input as one of a many accessibility gestures. Therefore, Flutter
148 * does not have an opportunity to react to said touch input. Instead, Flutter must be notified by
149 * Android of the desired action. Additionally, some accessibility systems use other input
150 * methods, such as speech, to take virtual actions. Android interprets those requests and then
151 * instructs the app to take the appropriate action.
152 */
154 int virtualViewId, @NonNull AccessibilityBridge.Action action) {
156 }
157
158 /**
159 * Instructs Flutter to perform the given {@code action} on the {@code SemanticsNode} referenced
160 * by the given {@code virtualViewId}, passing the given {@code args}.
161 */
163 int virtualViewId, @NonNull AccessibilityBridge.Action action, @Nullable Object args) {
165 }
166
167 /**
168 * Sets the {@link AccessibilityMessageHandler} which receives all events and requests that are
169 * parsed from the underlying accessibility channel.
170 */
172 this.handler = handler;
174 }
175
176 /**
177 * Handler that receives accessibility messages sent from Flutter to Android through a given
178 * {@link AccessibilityChannel}.
179 *
180 * <p>To register an {@code AccessibilityMessageHandler} with a {@link AccessibilityChannel}, see
181 * {@link AccessibilityChannel#setAccessibilityMessageHandler(AccessibilityMessageHandler)}.
182 */
183 public interface AccessibilityMessageHandler extends FlutterJNI.AccessibilityDelegate {
184 /** The Dart application would like the given {@code message} to be announced. */
185 void announce(@NonNull String message);
186
187 /** The user has tapped on the semantics node with the given {@code nodeId}. */
188 void onTap(int nodeId);
189
190 /** The user has long pressed on the semantics node with the given {@code nodeId}. */
191 void onLongPress(int nodeId);
192
193 /** The framework has requested focus on the semantics node with the given {@code nodeId}. */
194 void onFocus(int nodeId);
195
196 /** The user has opened a tooltip. */
197 void onTooltip(@NonNull String message);
198 }
199}
static void v(@NonNull String tag, @NonNull String message)
Definition Log.java:40
void setSemanticsEnabled(boolean enabled)
void setAccessibilityDelegate(@Nullable AccessibilityDelegate accessibilityDelegate)
void dispatchSemanticsAction(int nodeId, @NonNull AccessibilityBridge.Action action)
void dispatchSemanticsAction(int virtualViewId, @NonNull AccessibilityBridge.Action action, @Nullable Object args)
AccessibilityChannel( @NonNull BasicMessageChannel< Object > channel, @NonNull FlutterJNI flutterJNI)
final BasicMessageChannel.MessageHandler< Object > parsingMessageHandler
void dispatchSemanticsAction(int virtualViewId, @NonNull AccessibilityBridge.Action action)
void setAccessibilityMessageHandler(@Nullable AccessibilityMessageHandler handler)
AccessibilityChannel(@NonNull DartExecutor dartExecutor, @NonNull FlutterJNI flutterJNI)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Win32Message message
#define TAG()