| Flutter iOS Embedder |

accessibility_bridge.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef FLUTTER_SHELL_PLATFORM_COMMON_ACCESSIBILITY_BRIDGE_H_
6 #define FLUTTER_SHELL_PLATFORM_COMMON_ACCESSIBILITY_BRIDGE_H_
7
8 #include <unordered_map>
9
10 #include "flutter/fml/mapping.h"
11 #include "flutter/shell/platform/embedder/embedder.h"
12
13 #include "flutter/third_party/accessibility/ax/ax_event_generator.h"
14 #include "flutter/third_party/accessibility/ax/ax_tree.h"
15 #include "flutter/third_party/accessibility/ax/ax_tree_observer.h"
16 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_delegate.h"
17 #include "flutter/third_party/accessibility/ax/platform/ax_platform_tree_manager.h"
18
19 #include "flutter_platform_node_delegate.h"
20
21 namespace flutter {
22
23 //------------------------------------------------------------------------------
24 /// Use this class to maintain an accessibility tree. This class consumes
25 /// semantics updates from the embedder API and produces an accessibility tree
26 /// in the native format.
27 ///
28 /// The bridge creates an AXTree to hold the semantics data that comes from
29 /// Flutter semantics updates. The tree holds AXNode[s] which contain the
30 /// semantics information for semantics node. The AXTree resemble the Flutter
31 /// semantics tree in the Flutter framework. The bridge also uses
32 /// FlutterPlatformNodeDelegate to wrap each AXNode in order to provide
33 /// an accessibility tree in the native format.
34 ///
35 /// To use this class, one must subclass this class and provide their own
36 /// implementation of FlutterPlatformNodeDelegate.
37 ///
38 /// AccessibilityBridge must be created as a shared_ptr, since some methods
39 /// acquires its weak_ptr.
40 class AccessibilityBridge
41 : public std::enable_shared_from_this<AccessibilityBridge>,
42 public FlutterPlatformNodeDelegate::OwnerBridge,
43 public ui::AXPlatformTreeManager,
44 private ui::AXTreeObserver {
45 public:
46 //-----------------------------------------------------------------------------
47 /// @brief Creates a new instance of a accessibility bridge.
48 AccessibilityBridge();
49 virtual ~AccessibilityBridge();
50
51 //------------------------------------------------------------------------------
52 /// @brief Adds a semantics node update to the pending semantics update.
53 /// Calling this method alone will NOT update the semantics tree.
54 /// To flush the pending updates, call the CommitUpdates().
55 ///
56 /// @param[in] node A reference to the semantics node update.
57 void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2& node);
58
59 //------------------------------------------------------------------------------
60 /// @brief Adds a custom semantics action update to the pending semantics
61 /// update. Calling this method alone will NOT update the
62 /// semantics tree. To flush the pending updates, call the
63 /// CommitUpdates().
64 ///
65 /// @param[in] action A reference to the custom semantics action
66 /// update.
67 void AddFlutterSemanticsCustomActionUpdate(
68 const FlutterSemanticsCustomAction2& action);
69
70 //------------------------------------------------------------------------------
71 /// @brief Flushes the pending updates and applies them to this
72 /// accessibility bridge. Calling this with no pending updates
73 /// does nothing, and callers should call this method at the end
74 /// of an atomic batch to avoid leaving the tree in a unstable
75 /// state. For example if a node reparents from A to B, callers
76 /// should only call this method when both removal from A and
77 /// addition to B are in the pending updates.
78 void CommitUpdates();
79
80 //------------------------------------------------------------------------------
81 /// @brief Get the flutter platform node delegate with the given id from
82 /// this accessibility bridge. Returns expired weak_ptr if the
83 /// delegate associated with the id does not exist or has been
84 /// removed from the accessibility tree.
85 ///
86 /// @param[in] id The id of the flutter accessibility node you want
87 /// to retrieve.
88 std::weak_ptr<FlutterPlatformNodeDelegate>
89 GetFlutterPlatformNodeDelegateFromID(AccessibilityNodeId id) const;
90
91 //------------------------------------------------------------------------------
92 /// @brief Get the ax tree data from this accessibility bridge. The tree
93 /// data contains information such as the id of the node that
94 /// has the keyboard focus or the text selection range.
95 const ui::AXTreeData& GetAXTreeData() const;
96
97 //------------------------------------------------------------------------------
98 /// @brief Gets all pending accessibility events generated during
99 /// semantics updates. This is useful when deciding how to handle
100 /// events in AccessibilityBridgeDelegate::OnAccessibilityEvent in
101 /// case one may decide to handle an event differently based on
102 /// all pending events.
103 const std::vector<ui::AXEventGenerator::TargetedEvent> GetPendingEvents()
104 const;
105
106 // |AXTreeManager|
107 ui::AXNode* GetNodeFromTree(const ui::AXTreeID tree_id,
108 const ui::AXNode::AXID node_id) const override;
109
110 // |AXTreeManager|
111 ui::AXNode* GetNodeFromTree(const ui::AXNode::AXID node_id) const override;
112
113 // |AXTreeManager|
114 ui::AXTreeID GetTreeID() const override;
115
116 // |AXTreeManager|
117 ui::AXTreeID GetParentTreeID() const override;
118
119 // |AXTreeManager|
120 ui::AXNode* GetRootAsAXNode() const override;
121
122 // |AXTreeManager|
123 ui::AXNode* GetParentNodeFromParentTreeAsAXNode() const override;
124
125 // |AXTreeManager|
126 ui::AXTree* GetTree() const override;
127
128 // |AXPlatformTreeManager|
129 ui::AXPlatformNode* GetPlatformNodeFromTree(
130 const ui::AXNode::AXID node_id) const override;
131
132 // |AXPlatformTreeManager|
133 ui::AXPlatformNode* GetPlatformNodeFromTree(
134 const ui::AXNode& node) const override;
135
136 // |AXPlatformTreeManager|
137 ui::AXPlatformNodeDelegate* RootDelegate() const override;
138
139 protected:
140 //---------------------------------------------------------------------------
141 /// @brief Handle accessibility events generated due to accessibility
142 /// tree changes. These events are needed to be sent to native
143 /// accessibility system. See ui::AXEventGenerator::Event for
144 /// possible events.
145 ///
146 /// @param[in] targeted_event The object that contains both the
147 /// generated event and the event target.
148 virtual void OnAccessibilityEvent(
149 ui::AXEventGenerator::TargetedEvent targeted_event) = 0;
150
151 //---------------------------------------------------------------------------
152 /// @brief Creates a platform specific FlutterPlatformNodeDelegate.
153 /// Ownership passes to the caller. This method will be called
154 /// whenever a new AXNode is created in AXTree. Each platform
155 /// needs to implement this method in order to inject its
156 /// subclass into the accessibility bridge.
157 virtual std::shared_ptr<FlutterPlatformNodeDelegate>
158 CreateFlutterPlatformNodeDelegate() = 0;
159
160 private:
161 // See FlutterSemanticsNode in embedder.h
162 typedef struct {
163 int32_t id;
164 FlutterSemanticsFlags* flags;
165 FlutterSemanticsAction actions;
166 int32_t text_selection_base;
167 int32_t text_selection_extent;
168 int32_t scroll_child_count;
169 int32_t scroll_index;
170 double scroll_position;
171 double scroll_extent_max;
172 double scroll_extent_min;
173 std::string label;
174 std::string hint;
175 std::string value;
176 std::string increased_value;
177 std::string decreased_value;
178 std::string tooltip;
179 FlutterTextDirection text_direction;
180 FlutterRect rect;
181 FlutterTransformation transform;
182 std::vector<int32_t> children_in_traversal_order;
183 std::vector<int32_t> custom_accessibility_actions;
184 } SemanticsNode;
185
186 // See FlutterSemanticsCustomAction in embedder.h
187 typedef struct {
188 int32_t id;
189 FlutterSemanticsAction override_action;
190 std::string label;
191 std::string hint;
192 } SemanticsCustomAction;
193
194 std::unordered_map<AccessibilityNodeId,
195 std::shared_ptr<FlutterPlatformNodeDelegate>>
196 id_wrapper_map_;
197 std::unique_ptr<ui::AXTree> tree_;
198 ui::AXEventGenerator event_generator_;
199 std::unordered_map<int32_t, SemanticsNode> pending_semantics_node_updates_;
200 std::unordered_map<int32_t, SemanticsCustomAction>
201 pending_semantics_custom_action_updates_;
202 AccessibilityNodeId last_focused_id_ = ui::AXNode::kInvalidAXID;
203
204 void InitAXTree(const ui::AXTreeUpdate& initial_state);
205
206 // Create an update that removes any nodes that will be reparented by
207 // pending_semantics_updates_. Returns std::nullopt if none are reparented.
208 std::optional<ui::AXTreeUpdate> CreateRemoveReparentedNodesUpdate();
209
210 void GetSubTreeList(const SemanticsNode& target,
211 std::vector<SemanticsNode>& result);
212 void ConvertFlutterUpdate(const SemanticsNode& node,
213 ui::AXTreeUpdate& tree_update);
214 void SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,
215 const SemanticsNode& node);
216 void SetStateFromFlutterUpdate(ui::AXNodeData& node_data,
217 const SemanticsNode& node);
218 void SetActionsFromFlutterUpdate(ui::AXNodeData& node_data,
219 const SemanticsNode& node);
220 void SetBooleanAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
221 const SemanticsNode& node);
222 void SetIntAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
223 const SemanticsNode& node);
224 void SetIntListAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
225 const SemanticsNode& node);
226 void SetStringListAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
227 const SemanticsNode& node);
228 void SetNameFromFlutterUpdate(ui::AXNodeData& node_data,
229 const SemanticsNode& node);
230 void SetValueFromFlutterUpdate(ui::AXNodeData& node_data,
231 const SemanticsNode& node);
232 void SetTooltipFromFlutterUpdate(ui::AXNodeData& node_data,
233 const SemanticsNode& node);
234 void SetTreeData(const SemanticsNode& node, ui::AXTreeUpdate& tree_update);
235 SemanticsNode FromFlutterSemanticsNode(
236 const FlutterSemanticsNode2& flutter_node);
237 SemanticsCustomAction FromFlutterSemanticsCustomAction(
238 const FlutterSemanticsCustomAction2& flutter_custom_action);
239
240 // |AXTreeObserver|
241 void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
242
243 // |AXTreeObserver|
244 void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
245
246 // |AXTreeObserver|
247 void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
248
249 // |AXTreeObserver|
250 void OnNodeDeleted(ui::AXTree* tree, AccessibilityNodeId node_id) override;
251
252 // |AXTreeObserver|
253 void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override;
254
255 // |AXTreeObserver|
256 void OnRoleChanged(ui::AXTree* tree,
257 ui::AXNode* node,
258 ax::mojom::Role old_role,
259 ax::mojom::Role new_role) override;
260
261 // |AXTreeObserver|
262 void OnNodeDataChanged(ui::AXTree* tree,
263 const ui::AXNodeData& old_node_data,
264 const ui::AXNodeData& new_node_data) override;
265
266 // |AXTreeObserver|
267 void OnAtomicUpdateFinished(
268 ui::AXTree* tree,
269 bool root_changed,
270 const std::vector<ui::AXTreeObserver::Change>& changes) override;
271
272 // |FlutterPlatformNodeDelegate::OwnerBridge|
273 void SetLastFocusedId(AccessibilityNodeId node_id) override;
274
275 // |FlutterPlatformNodeDelegate::OwnerBridge|
276 AccessibilityNodeId GetLastFocusedId() override;
277
278 // |FlutterPlatformNodeDelegate::OwnerBridge|
279 gfx::NativeViewAccessible GetNativeAccessibleFromId(
280 AccessibilityNodeId id) override;
281
282 // |FlutterPlatformNodeDelegate::OwnerBridge|
283 gfx::RectF RelativeToGlobalBounds(const ui::AXNode* node,
284 bool& offscreen,
285 bool clip_bounds) override;
286
287 BASE_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge);
288 };
289
290 } // namespace flutter
291
292 #endif // FLUTTER_SHELL_PLATFORM_COMMON_ACCESSIBILITY_BRIDGE_H_
flutter::AccessibilityBridge::GetTree
ui::AXTree * GetTree() const override
Definition: accessibility_bridge.cc:705
flutter::AccessibilityBridge::RootDelegate
ui::AXPlatformNodeDelegate * RootDelegate() const override
Definition: accessibility_bridge.cc:724
flutter::AccessibilityBridge::GetFlutterPlatformNodeDelegateFromID
std::weak_ptr< FlutterPlatformNodeDelegate > GetFlutterPlatformNodeDelegateFromID(AccessibilityNodeId id) const
Get the flutter platform node delegate with the given id from this accessibility bridge....
Definition: accessibility_bridge.cc:131
flutter::AccessibilityBridge::CreateFlutterPlatformNodeDelegate
virtual std::shared_ptr< FlutterPlatformNodeDelegate > CreateFlutterPlatformNodeDelegate()=0
Creates a platform specific FlutterPlatformNodeDelegate. Ownership passes to the caller....
flutter::AccessibilityBridge::AddFlutterSemanticsNodeUpdate
void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2 &node)
Adds a semantics node update to the pending semantics update. Calling this method alone will NOT upda...
Definition: accessibility_bridge.cc:39
flutter::AccessibilityBridge::AddFlutterSemanticsCustomActionUpdate
void AddFlutterSemanticsCustomActionUpdate(const FlutterSemanticsCustomAction2 &action)
Adds a custom semantics action update to the pending semantics update. Calling this method alone will...
Definition: accessibility_bridge.cc:44
flutter::AccessibilityBridge::GetPlatformNodeFromTree
ui::AXPlatformNode * GetPlatformNodeFromTree(const ui::AXNode::AXID node_id) const override
Definition: accessibility_bridge.cc:709
flutter::AccessibilityBridge::GetAXTreeData
const ui::AXTreeData & GetAXTreeData() const
Get the ax tree data from this accessibility bridge. The tree data contains information such as the i...
Definition: accessibility_bridge.cc:141
flutter::AccessibilityBridge::GetParentTreeID
ui::AXTreeID GetParentTreeID() const override
Definition: accessibility_bridge.cc:693
flutter::AccessibilityBridge::~AccessibilityBridge
virtual ~AccessibilityBridge()
flutter::AccessibilityBridge::GetRootAsAXNode
ui::AXNode * GetRootAsAXNode() const override
Definition: accessibility_bridge.cc:697
flutter::AccessibilityBridge::GetParentNodeFromParentTreeAsAXNode
ui::AXNode * GetParentNodeFromParentTreeAsAXNode() const override
Definition: accessibility_bridge.cc:701
flutter::AccessibilityBridge::AccessibilityBridge
AccessibilityBridge()
Creates a new instance of a accessibility bridge.
Definition: accessibility_bridge.cc:23
flutter::AccessibilityBridge::OnAccessibilityEvent
virtual void OnAccessibilityEvent(ui::AXEventGenerator::TargetedEvent targeted_event)=0
Handle accessibility events generated due to accessibility tree changes. These events are needed to b...
flutter::AccessibilityBridge::GetTreeID
ui::AXTreeID GetTreeID() const override
Definition: accessibility_bridge.cc:689
flutter::AccessibilityBridge::GetPendingEvents
const std::vector< ui::AXEventGenerator::TargetedEvent > GetPendingEvents() const
Gets all pending accessibility events generated during semantics updates. This is useful when decidin...
Definition: accessibility_bridge.cc:146
flutter::AccessibilityBridge::CommitUpdates
void CommitUpdates()
Flushes the pending updates and applies them to this accessibility bridge. Calling this with no pendi...
Definition: accessibility_bridge.cc:50
flutter::AccessibilityBridge::GetNodeFromTree
ui::AXNode * GetNodeFromTree(const ui::AXTreeID tree_id, const ui::AXNode::AXID node_id) const override
Definition: accessibility_bridge.cc:678
flutter_platform_node_delegate.h
flutter
Definition: accessibility_bridge.h:26
flutter::AccessibilityNodeId
ui::AXNode::AXID AccessibilityNodeId
Definition: flutter_platform_node_delegate.h:15