Flutter Engine
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 SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_SEMANTICS_OBJECT_H_
6 #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_SEMANTICS_OBJECT_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 
19 
20 /**
21  * A node in the iOS semantics tree.
22  */
23 @interface SemanticsObject : UIAccessibilityElement
24 
25 /**
26  * The globally unique identifier for this node.
27  */
28 @property(nonatomic, readonly) int32_t uid;
29 
30 /**
31  * The parent of this node in the node tree. Will be nil for the root node and
32  * during transient state changes.
33  */
34 @property(nonatomic, readonly) SemanticsObject* parent;
35 
36 /**
37  * The accessibility bridge that this semantics object is attached to. This
38  * object may use the bridge to access contextual application information. A weak
39  * pointer is used because the platform view owns the accessibility bridge.
40  * If you are referencing this property from an iOS callback, be sure to
41  * use `isAccessibilityBridgeActive` to protect against the case where this
42  * node may be orphaned.
43  */
45 
46 /**
47  * Due to the fact that VoiceOver may hold onto SemanticObjects even after it shuts down,
48  * there can be situations where the AccessibilityBridge is shutdown, but the SemanticObject
49  * will still be alive. If VoiceOver is turned on again, it may try to access this orphaned
50  * SemanticObject. Methods that are called from the accessiblity framework should use
51  * this to guard against this case by just returning early if its bridge has been shutdown.
52  *
53  * See https://github.com/flutter/flutter/issues/43795 for more information.
54  */
56 
57 /**
58  * The semantics node used to produce this semantics object.
59  */
60 @property(nonatomic, readonly) flutter::SemanticsNode node;
61 
62 /**
63  * Updates this semantics object using data from the `node` argument.
64  */
65 - (void)setSemanticsNode:(const flutter::SemanticsNode*)node NS_REQUIRES_SUPER;
66 
67 /**
68  * Whether this semantics object has child semantics objects.
69  */
70 @property(nonatomic, readonly) BOOL hasChildren;
71 
72 /**
73  * Direct children of this semantics object. Each child's `parent` property must
74  * be equal to this object.
75  */
76 @property(nonatomic, strong) NSArray<SemanticsObject*>* children;
77 
78 /**
79  * Used if this SemanticsObject is for a platform view.
80  */
82 
83 - (void)replaceChildAtIndex:(NSInteger)index withChild:(SemanticsObject*)child;
84 
85 - (BOOL)nodeWillCauseLayoutChange:(const flutter::SemanticsNode*)node;
86 
87 #pragma mark - Designated initializers
88 
89 - (instancetype)init __attribute__((unavailable("Use initWithBridge instead")));
90 - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
91  uid:(int32_t)uid NS_DESIGNATED_INITIALIZER;
92 
93 - (BOOL)nodeWillCauseScroll:(const flutter::SemanticsNode*)node;
94 - (BOOL)nodeShouldTriggerAnnouncement:(const flutter::SemanticsNode*)node;
95 - (void)collectRoutes:(NSMutableArray<SemanticsObject*>*)edges;
96 - (NSString*)routeName;
97 - (BOOL)onCustomAccessibilityAction:(FlutterCustomAccessibilityAction*)action;
98 
99 @end
100 
101 /**
102  * An implementation of UIAccessibilityCustomAction which also contains the
103  * Flutter uid.
104  */
105 @interface FlutterCustomAccessibilityAction : UIAccessibilityCustomAction
106 
107 /**
108  * The uid of the action defined by the flutter application.
109  */
110 @property(nonatomic) int32_t uid;
111 
112 @end
113 
114 /**
115  * The default implementation of `SemanticsObject` for most accessibility elements
116  * in the iOS accessibility tree.
117  *
118  * Use this implementation for nodes that do not need to be expressed via UIKit-specific
119  * protocols (it only implements NSObject).
120  *
121  * See also:
122  * * TextInputSemanticsObject, which implements `UITextInput` protocol to expose
123  * editable text widgets to a11y.
124  */
126 @end
127 
128 /**
129  * Designated to act as an accessibility container of a platform view.
130  *
131  * This object does not take any accessibility actions on its own, nor has any accessibility
132  * label/value/trait/hint... on its own. The accessibility data will be handled by the platform
133  * view.
134  *
135  * See also:
136  * * `SemanticsObject` for the other type of semantics objects.
137  * * `FlutterSemanticsObject` for default implementation of `SemanticsObject`.
138  */
139 @interface FlutterPlatformViewSemanticsContainer : UIAccessibilityElement
140 
141 /**
142  * The position inside an accessibility container.
143  */
144 @property(nonatomic) NSInteger index;
145 
146 - (instancetype)init __attribute__((unavailable("Use initWithAccessibilityContainer: instead")));
147 
148 - (instancetype)initWithSemanticsObject:(SemanticsObject*)object;
149 
150 @end
151 
152 /// A proxy class for SemanticsObject and UISwitch. For most Accessibility and
153 /// SemanticsObject methods it delegates to the semantics object, otherwise it
154 /// sends messages to the UISwitch.
155 @interface FlutterSwitchSemanticsObject : UISwitch
156 - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject;
157 @end
158 
159 /**
160  * Represents a semantics object that has children and hence has to be presented to the OS as a
161  * UIAccessibilityContainer.
162  *
163  * The SemanticsObject class cannot implement the UIAccessibilityContainer protocol because an
164  * object that returns YES for isAccessibilityElement cannot also implement
165  * UIAccessibilityContainer.
166  *
167  * With the help of SemanticsObjectContainer, the hierarchy of semantic objects received from
168  * the framework, such as:
169  *
170  * SemanticsObject1
171  * SemanticsObject2
172  * SemanticsObject3
173  * SemanticsObject4
174  *
175  * is translated into the following hierarchy, which is understood by iOS:
176  *
177  * SemanticsObjectContainer1
178  * SemanticsObject1
179  * SemanticsObjectContainer2
180  * SemanticsObject2
181  * SemanticsObject3
182  * SemanticsObject4
183  *
184  * From Flutter's view of the world (the first tree seen above), we construct iOS's view of the
185  * world (second tree) as follows: We replace each SemanticsObjects that has children with a
186  * SemanticsObjectContainer, which has the original SemanticsObject and its children as children.
187  *
188  * SemanticsObjects have semantic information attached to them which is interpreted by
189  * VoiceOver (they return YES for isAccessibilityElement). The SemanticsObjectContainers are just
190  * there for structure and they don't provide any semantic information to VoiceOver (they return
191  * NO for isAccessibilityElement).
192  */
193 @interface SemanticsObjectContainer : UIAccessibilityElement
194 - (instancetype)init NS_UNAVAILABLE;
195 + (instancetype)new NS_UNAVAILABLE;
196 - (instancetype)initWithAccessibilityContainer:(id)container NS_UNAVAILABLE;
197 - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject
198  bridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
199  NS_DESIGNATED_INITIALIZER;
200 
201 @property(nonatomic, weak) SemanticsObject* semanticsObject;
202 
203 @end
204 
205 #endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_SEMANTICS_OBJECT_H_
instancetype NS_UNAVAILABLE()
FlutterPlatformViewSemanticsContainer * platformViewSemanticsContainer
auto WeakPtr(std::shared_ptr< T > pointer)
(unavailable("Use initWithBridge instead" __attribute__()
NSArray< SemanticsObject * > * children
Definition: ascii_trie.cc:9
fml::WeakPtr< flutter::AccessibilityBridgeIos > bridge
SemanticsObject * parent
constexpr int32_t kRootNodeId
flutter::SemanticsNode node
NSString * routeName()
BOOL isAccessibilityBridgeAlive()