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