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"
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 
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, assign) 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, strong) 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, strong) 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  */
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  */
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  */
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  */
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.
183 
184 @end
185 
186 /// The semantics object for scrollable. This class creates an UIScrollView to interact with the
187 /// iOS.
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:348
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:400
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:164
FlutterPlatformViewSemanticsContainer
Definition: SemanticsObject.h:168
FlutterTouchInterceptingView
Definition: FlutterPlatformViews.mm:988
SemanticsObject::uid
int32_t uid
Definition: SemanticsObject.h:35
-[SemanticsObject accessibilityBridgeDidFinishUpdate]
void accessibilityBridgeDidFinishUpdate()
Definition: SemanticsObject.mm:356
SemanticsObjectContainer
Definition: SemanticsObject.h:226
-[SemanticsObject __attribute__]
(unavailable("Use initWithBridge instead" __attribute__()
FlutterScrollableSemanticsObject
Definition: SemanticsObject.h:188
SemanticsObject
Definition: SemanticsObject.h:30