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