| Flutter iOS Embedder |

SemanticsObject.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_DARWIN_IOS_FRAMEWORK_SOURCE_SEMANTICSOBJECT_H_
6 #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_SEMANTICSOBJECT_H_
7
8 #import <UIKit/UIKit.h>
9
10 #include "flutter/fml/macros.h"
11 #include "flutter/fml/memory/weak_ptr.h"
12 #include "flutter/lib/ui/semantics/semantics_node.h"
13 #import "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h"
14
15 constexpr int32_t kRootNodeId = 0;
16 // This can be arbitrary number as long as it is bigger than 0.
17 constexpr float kScrollExtentMaxForInf = 1000;
18
19 @class FlutterCustomAccessibilityAction;
20 @class FlutterPlatformViewSemanticsContainer;
21 @class FlutterTouchInterceptingView;
22
23 /**
24 * A node in the iOS semantics tree. This object is a wrapper over a native accessibiliy
25 * object, which is stored in the property `nativeAccessibility`. In the most case, the
26 * `nativeAccessibility` directly returns this object. Some subclasses such as the
27 * `FlutterScrollableSemanticsObject` creates a native `UIScrollView` as its `nativeAccessibility`
28 * so that it can interact with iOS.
29 */
30 @interface SemanticsObject : UIAccessibilityElement
31
32 /**
33 * The globally unique identifier for this node.
34 */
35 @property(nonatomic, readonly) int32_t uid;
36
37 /**
38 * The parent of this node in the node tree. Will be nil for the root node and
39 * during transient state changes.
40 */
41 @property(nonatomic, weak, readonly) SemanticsObject* parent;
42
43 /**
44 * The accessibility bridge that this semantics object is attached to. This
45 * object may use the bridge to access contextual application information. A weak
46 * pointer is used because the platform view owns the accessibility bridge.
47 * If you are referencing this property from an iOS callback, be sure to
48 * use `isAccessibilityBridgeActive` to protect against the case where this
49 * node may be orphaned.
50 */
51 @property(nonatomic, readonly) fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge;
52
53 /**
54 * The semantics node used to produce this semantics object.
55 */
56 @property(nonatomic, readonly) flutter::SemanticsNode node;
57
58 /**
59 * Whether this semantics object has child semantics objects.
60 */
61 @property(nonatomic, readonly) BOOL hasChildren;
62
63 /**
64 * Direct children of this semantics object. Each child's `parent` property must
65 * be equal to this object.
66 */
67 @property(nonatomic, copy) NSArray<SemanticsObject*>* children;
68
69 /**
70 * Direct children of this semantics object in hit test order. Each child's `parent` property
71 * must be equal to this object.
72 */
73 @property(nonatomic, copy) NSArray<SemanticsObject*>* childrenInHitTestOrder;
74
75 /**
76 * The UIAccessibility that represents this object.
77 *
78 * By default, this return self. Subclasses can override to return different
79 * objects to represent them. For example, FlutterScrollableSemanticsObject[s]
80 * maintain UIScrollView[s] to represent their UIAccessibility[s].
81 */
82 @property(nonatomic, readonly) id nativeAccessibility;
83
84 /**
85 * Due to the fact that VoiceOver may hold onto SemanticObjects even after it shuts down,
86 * there can be situations where the AccessibilityBridge is shutdown, but the SemanticObject
87 * will still be alive. If VoiceOver is turned on again, it may try to access this orphaned
88 * SemanticObject. Methods that are called from the accessiblity framework should use
89 * this to guard against this case by just returning early if its bridge has been shutdown.
90 *
91 * See https://github.com/flutter/flutter/issues/43795 for more information.
92 */
93 - (BOOL)isAccessibilityBridgeAlive;
94
95 /**
96 * Updates this semantics object using data from the `node` argument.
97 */
98 - (void)setSemanticsNode:(const flutter::SemanticsNode*)node NS_REQUIRES_SUPER;
99
100 - (void)replaceChildAtIndex:(NSInteger)index withChild:(SemanticsObject*)child;
101
102 - (BOOL)nodeWillCauseLayoutChange:(const flutter::SemanticsNode*)node;
103
104 - (BOOL)nodeWillCauseScroll:(const flutter::SemanticsNode*)node;
105
106 - (BOOL)nodeShouldTriggerAnnouncement:(const flutter::SemanticsNode*)node;
107
108 - (void)collectRoutes:(NSMutableArray<SemanticsObject*>*)edges;
109
110 - (NSString*)routeName;
111
112 - (BOOL)onCustomAccessibilityAction:(FlutterCustomAccessibilityAction*)action;
113
114 /**
115 * Called after accessibility bridge finishes a semantics update.
116 *
117 * Subclasses can override this method if they contain states that can only be
118 * updated once every node in the accessibility tree has finished updating.
119 */
120 - (void)accessibilityBridgeDidFinishUpdate;
121
122 #pragma mark - Designated initializers
123
124 - (instancetype)init __attribute__((unavailable("Use initWithBridge instead")));
125 - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
126 uid:(int32_t)uid NS_DESIGNATED_INITIALIZER;
127
128 @end
129
130 /**
131 * An implementation of UIAccessibilityCustomAction which also contains the
132 * Flutter uid.
133 */
134 @interface FlutterCustomAccessibilityAction : UIAccessibilityCustomAction
135
136 /**
137 * The uid of the action defined by the flutter application.
138 */
139 @property(nonatomic) int32_t uid;
140
141 @end
142
143 /**
144 * The default implementation of `SemanticsObject` for most accessibility elements
145 * in the iOS accessibility tree.
146 *
147 * Use this implementation for nodes that do not need to be expressed via UIKit-specific
148 * protocols (it only implements NSObject).
149 *
150 * See also:
151 * * TextInputSemanticsObject, which implements `UITextInput` protocol to expose
152 * editable text widgets to a11y.
153 */
154 @interface FlutterSemanticsObject : SemanticsObject
155 @end
156
157 /**
158 * Designated to act as an accessibility container of a platform view.
159 *
160 * This object does not take any accessibility actions on its own, nor has any accessibility
161 * label/value/trait/hint... on its own. The accessibility data will be handled by the platform
162 * view.
163 *
164 * See also:
165 * * `SemanticsObject` for the other type of semantics objects.
166 * * `FlutterSemanticsObject` for default implementation of `SemanticsObject`.
167 */
168 @interface FlutterPlatformViewSemanticsContainer : SemanticsObject
169
170 - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
171 uid:(int32_t)uid NS_UNAVAILABLE;
172
173 - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
174 uid:(int32_t)uid
175 platformView:(FlutterTouchInterceptingView*)platformView
176 NS_DESIGNATED_INITIALIZER;
177
178 @end
179
180 /// The semantics object for switch buttons. This class creates an UISwitch to interact with the
181 /// iOS.
182 @interface FlutterSwitchSemanticsObject : SemanticsObject
183
184 @end
185
186 /// The semantics object for scrollable. This class creates an UIScrollView to interact with the
187 /// iOS.
188 @interface FlutterScrollableSemanticsObject : SemanticsObject
189
190 @end
191
192 /**
193 * Represents a semantics object that has children and hence has to be presented to the OS as a
194 * UIAccessibilityContainer.
195 *
196 * The SemanticsObject class cannot implement the UIAccessibilityContainer protocol because an
197 * object that returns YES for isAccessibilityElement cannot also implement
198 * UIAccessibilityContainer.
199 *
200 * With the help of SemanticsObjectContainer, the hierarchy of semantic objects received from
201 * the framework, such as:
202 *
203 * SemanticsObject1
204 * SemanticsObject2
205 * SemanticsObject3
206 * SemanticsObject4
207 *
208 * is translated into the following hierarchy, which is understood by iOS:
209 *
210 * SemanticsObjectContainer1
211 * SemanticsObject1
212 * SemanticsObjectContainer2
213 * SemanticsObject2
214 * SemanticsObject3
215 * SemanticsObject4
216 *
217 * From Flutter's view of the world (the first tree seen above), we construct iOS's view of the
218 * world (second tree) as follows: We replace each SemanticsObjects that has children with a
219 * SemanticsObjectContainer, which has the original SemanticsObject and its children as children.
220 *
221 * SemanticsObjects have semantic information attached to them which is interpreted by
222 * VoiceOver (they return YES for isAccessibilityElement). The SemanticsObjectContainers are just
223 * there for structure and they don't provide any semantic information to VoiceOver (they return
224 * NO for isAccessibilityElement).
225 */
226 @interface SemanticsObjectContainer : UIAccessibilityElement
227 - (instancetype)init NS_UNAVAILABLE;
228 + (instancetype)new NS_UNAVAILABLE;
229 - (instancetype)initWithAccessibilityContainer:(id)container NS_UNAVAILABLE;
230 - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject
231 bridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
232 NS_DESIGNATED_INITIALIZER;
233
234 @property(nonatomic, weak) SemanticsObject* semanticsObject;
235
236 @end
237
238 #endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_SEMANTICSOBJECT_H_
accessibility_bridge_ios.h
SemanticsObject::parent
SemanticsObject * parent
Definition: SemanticsObject.h:41
FlutterCustomAccessibilityAction
Definition: SemanticsObject.h:134
-[SemanticsObject isAccessibilityBridgeAlive]
BOOL isAccessibilityBridgeAlive()
Definition: SemanticsObject.mm:324
SemanticsObjectContainer::semanticsObject
SemanticsObject * semanticsObject
Definition: SemanticsObject.h:234
SemanticsObject::bridge
fml::WeakPtr< flutter::AccessibilityBridgeIos > bridge
Definition: SemanticsObject.h:51
-[SemanticsObject routeName]
NSString * routeName()
Definition: SemanticsObject.mm:376
FlutterSemanticsObject
Definition: SemanticsObject.h:154
SemanticsObject::childrenInHitTestOrder
NSArray< SemanticsObject * > * childrenInHitTestOrder
Definition: SemanticsObject.h:73
flutter
Definition: accessibility_bridge.h:28
kScrollExtentMaxForInf
constexpr float kScrollExtentMaxForInf
Definition: SemanticsObject.h:17
SemanticsObject::node
flutter::SemanticsNode node
Definition: SemanticsObject.h:56
FlutterSwitchSemanticsObject
Definition: SemanticsObject.h:182
kRootNodeId
constexpr int32_t kRootNodeId
Definition: SemanticsObject.h:15
SemanticsObject::hasChildren
BOOL hasChildren
Definition: SemanticsObject.h:61
SemanticsObject::children
NSArray< SemanticsObject * > * children
Definition: SemanticsObject.h:67
SemanticsObject::nativeAccessibility
id nativeAccessibility
Definition: SemanticsObject.h:82
NS_UNAVAILABLE
instancetype init NS_UNAVAILABLE
Definition: FlutterTextInputPlugin.h:169
FlutterPlatformViewSemanticsContainer
Definition: SemanticsObject.h:168
FlutterTouchInterceptingView
Definition: FlutterPlatformViews.mm:990
SemanticsObject::uid
int32_t uid
Definition: SemanticsObject.h:35
-[SemanticsObject accessibilityBridgeDidFinishUpdate]
void accessibilityBridgeDidFinishUpdate()
Definition: SemanticsObject.mm:332
SemanticsObjectContainer
Definition: SemanticsObject.h:226
-[SemanticsObject __attribute__]
(unavailable("Use initWithBridge instead" __attribute__()
FlutterScrollableSemanticsObject
Definition: SemanticsObject.h:188
SemanticsObject
Definition: SemanticsObject.h:30