• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5part of ui;
6
7/// The possible actions that can be conveyed from the operating system
8/// accessibility APIs to a semantics node.
9class SemanticsAction {
10  const SemanticsAction._(this.index);
11
12  static const int _kTapIndex = 1 << 0;
13  static const int _kLongPressIndex = 1 << 1;
14  static const int _kScrollLeftIndex = 1 << 2;
15  static const int _kScrollRightIndex = 1 << 3;
16  static const int _kScrollUpIndex = 1 << 4;
17  static const int _kScrollDownIndex = 1 << 5;
18  static const int _kIncreaseIndex = 1 << 6;
19  static const int _kDecreaseIndex = 1 << 7;
20  static const int _kShowOnScreenIndex = 1 << 8;
21  static const int _kMoveCursorForwardByCharacterIndex = 1 << 9;
22  static const int _kMoveCursorBackwardByCharacterIndex = 1 << 10;
23  static const int _kSetSelectionIndex = 1 << 11;
24  static const int _kCopyIndex = 1 << 12;
25  static const int _kCutIndex = 1 << 13;
26  static const int _kPasteIndex = 1 << 14;
27  static const int _kDidGainAccessibilityFocusIndex = 1 << 15;
28  static const int _kDidLoseAccessibilityFocusIndex = 1 << 16;
29  static const int _kCustomAction = 1 << 17;
30  static const int _kDismissIndex = 1 << 18;
31  static const int _kMoveCursorForwardByWordIndex = 1 << 19;
32  static const int _kMoveCursorBackwardByWordIndex = 1 << 20;
33
34  /// The numerical value for this action.
35  ///
36  /// Each action has one bit set in this bit field.
37  final int index;
38
39  /// The equivalent of a user briefly tapping the screen with the finger
40  /// without moving it.
41  static const SemanticsAction tap = SemanticsAction._(_kTapIndex);
42
43  /// The equivalent of a user pressing and holding the screen with the finger
44  /// for a few seconds without moving it.
45  static const SemanticsAction longPress = SemanticsAction._(_kLongPressIndex);
46
47  /// The equivalent of a user moving their finger across the screen from right
48  /// to left.
49  ///
50  /// This action should be recognized by controls that are horizontally
51  /// scrollable.
52  static const SemanticsAction scrollLeft =
53      SemanticsAction._(_kScrollLeftIndex);
54
55  /// The equivalent of a user moving their finger across the screen from left
56  /// to right.
57  ///
58  /// This action should be recognized by controls that are horizontally
59  /// scrollable.
60  static const SemanticsAction scrollRight =
61      SemanticsAction._(_kScrollRightIndex);
62
63  /// The equivalent of a user moving their finger across the screen from
64  /// bottom to top.
65  ///
66  /// This action should be recognized by controls that are vertically
67  /// scrollable.
68  static const SemanticsAction scrollUp = SemanticsAction._(_kScrollUpIndex);
69
70  /// The equivalent of a user moving their finger across the screen from top
71  /// to bottom.
72  ///
73  /// This action should be recognized by controls that are vertically
74  /// scrollable.
75  static const SemanticsAction scrollDown =
76      SemanticsAction._(_kScrollDownIndex);
77
78  /// A request to increase the value represented by the semantics node.
79  ///
80  /// For example, this action might be recognized by a slider control.
81  static const SemanticsAction increase = SemanticsAction._(_kIncreaseIndex);
82
83  /// A request to decrease the value represented by the semantics node.
84  ///
85  /// For example, this action might be recognized by a slider control.
86  static const SemanticsAction decrease = SemanticsAction._(_kDecreaseIndex);
87
88  /// A request to fully show the semantics node on screen.
89  ///
90  /// For example, this action might be send to a node in a scrollable list that
91  /// is partially off screen to bring it on screen.
92  static const SemanticsAction showOnScreen =
93      SemanticsAction._(_kShowOnScreenIndex);
94
95  /// Move the cursor forward by one character.
96  ///
97  /// This is for example used by the cursor control in text fields.
98  ///
99  /// The action includes a boolean argument, which indicates whether the cursor
100  /// movement should extend (or start) a selection.
101  static const SemanticsAction moveCursorForwardByCharacter =
102      SemanticsAction._(_kMoveCursorForwardByCharacterIndex);
103
104  /// Move the cursor backward by one character.
105  ///
106  /// This is for example used by the cursor control in text fields.
107  ///
108  /// The action includes a boolean argument, which indicates whether the cursor
109  /// movement should extend (or start) a selection.
110  static const SemanticsAction moveCursorBackwardByCharacter =
111      SemanticsAction._(_kMoveCursorBackwardByCharacterIndex);
112
113  /// Set the text selection to the given range.
114  ///
115  /// The provided argument is a Map<String, int> which includes the keys `base`
116  /// and `extent` indicating where the selection within the `value` of the
117  /// semantics node should start and where it should end. Values for both
118  /// keys can range from 0 to length of `value` (inclusive).
119  ///
120  /// Setting `base` and `extent` to the same value will move the cursor to
121  /// that position (without selecting anything).
122  static const SemanticsAction setSelection =
123      SemanticsAction._(_kSetSelectionIndex);
124
125  /// Copy the current selection to the clipboard.
126  static const SemanticsAction copy = SemanticsAction._(_kCopyIndex);
127
128  /// Cut the current selection and place it in the clipboard.
129  static const SemanticsAction cut = SemanticsAction._(_kCutIndex);
130
131  /// Paste the current content of the clipboard.
132  static const SemanticsAction paste = SemanticsAction._(_kPasteIndex);
133
134  /// Indicates that the nodes has gained accessibility focus.
135  ///
136  /// This handler is invoked when the node annotated with this handler gains
137  /// the accessibility focus. The accessibility focus is the
138  /// green (on Android with TalkBack) or black (on iOS with VoiceOver)
139  /// rectangle shown on screen to indicate what element an accessibility
140  /// user is currently interacting with.
141  ///
142  /// The accessibility focus is different from the input focus. The input focus
143  /// is usually held by the element that currently responds to keyboard inputs.
144  /// Accessibility focus and input focus can be held by two different nodes!
145  static const SemanticsAction didGainAccessibilityFocus =
146      SemanticsAction._(_kDidGainAccessibilityFocusIndex);
147
148  /// Indicates that the nodes has lost accessibility focus.
149  ///
150  /// This handler is invoked when the node annotated with this handler
151  /// loses the accessibility focus. The accessibility focus is
152  /// the green (on Android with TalkBack) or black (on iOS with VoiceOver)
153  /// rectangle shown on screen to indicate what element an accessibility
154  /// user is currently interacting with.
155  ///
156  /// The accessibility focus is different from the input focus. The input focus
157  /// is usually held by the element that currently responds to keyboard inputs.
158  /// Accessibility focus and input focus can be held by two different nodes!
159  static const SemanticsAction didLoseAccessibilityFocus =
160      SemanticsAction._(_kDidLoseAccessibilityFocusIndex);
161
162  /// Indicates that the user has invoked a custom accessibility action.
163  ///
164  /// This handler is added automatically whenever a custom accessibility
165  /// action is added to a semantics node.
166  static const SemanticsAction customAction = SemanticsAction._(_kCustomAction);
167
168  /// A request that the node should be dismissed.
169  ///
170  /// A [Snackbar], for example, may have a dismiss action to indicate to the
171  /// user that it can be removed after it is no longer relevant. On Android,
172  /// (with TalkBack) special hint text is spoken when focusing the node and
173  /// a custom action is availible in the local context menu. On iOS,
174  /// (with VoiceOver) users can perform a standard gesture to dismiss it.
175  static const SemanticsAction dismiss = SemanticsAction._(_kDismissIndex);
176
177  /// Move the cursor forward by one word.
178  ///
179  /// This is for example used by the cursor control in text fields.
180  ///
181  /// The action includes a boolean argument, which indicates whether the cursor
182  /// movement should extend (or start) a selection.
183  static const SemanticsAction moveCursorForwardByWord =
184      SemanticsAction._(_kMoveCursorForwardByWordIndex);
185
186  /// Move the cursor backward by one word.
187  ///
188  /// This is for example used by the cursor control in text fields.
189  ///
190  /// The action includes a boolean argument, which indicates whether the cursor
191  /// movement should extend (or start) a selection.
192  static const SemanticsAction moveCursorBackwardByWord =
193      SemanticsAction._(_kMoveCursorBackwardByWordIndex);
194
195  /// The possible semantics actions.
196  ///
197  /// The map's key is the [index] of the action and the value is the action
198  /// itself.
199  static const Map<int, SemanticsAction> values = <int, SemanticsAction>{
200    _kTapIndex: tap,
201    _kLongPressIndex: longPress,
202    _kScrollLeftIndex: scrollLeft,
203    _kScrollRightIndex: scrollRight,
204    _kScrollUpIndex: scrollUp,
205    _kScrollDownIndex: scrollDown,
206    _kIncreaseIndex: increase,
207    _kDecreaseIndex: decrease,
208    _kShowOnScreenIndex: showOnScreen,
209    _kMoveCursorForwardByCharacterIndex: moveCursorForwardByCharacter,
210    _kMoveCursorBackwardByCharacterIndex: moveCursorBackwardByCharacter,
211    _kSetSelectionIndex: setSelection,
212    _kCopyIndex: copy,
213    _kCutIndex: cut,
214    _kPasteIndex: paste,
215    _kDidGainAccessibilityFocusIndex: didGainAccessibilityFocus,
216    _kDidLoseAccessibilityFocusIndex: didLoseAccessibilityFocus,
217    _kCustomAction: customAction,
218    _kDismissIndex: dismiss,
219    _kMoveCursorForwardByWordIndex: moveCursorForwardByWord,
220    _kMoveCursorBackwardByWordIndex: moveCursorBackwardByWord,
221  };
222
223  @override
224  String toString() {
225    switch (index) {
226      case _kTapIndex:
227        return 'SemanticsAction.tap';
228      case _kLongPressIndex:
229        return 'SemanticsAction.longPress';
230      case _kScrollLeftIndex:
231        return 'SemanticsAction.scrollLeft';
232      case _kScrollRightIndex:
233        return 'SemanticsAction.scrollRight';
234      case _kScrollUpIndex:
235        return 'SemanticsAction.scrollUp';
236      case _kScrollDownIndex:
237        return 'SemanticsAction.scrollDown';
238      case _kIncreaseIndex:
239        return 'SemanticsAction.increase';
240      case _kDecreaseIndex:
241        return 'SemanticsAction.decrease';
242      case _kShowOnScreenIndex:
243        return 'SemanticsAction.showOnScreen';
244      case _kMoveCursorForwardByCharacterIndex:
245        return 'SemanticsAction.moveCursorForwardByCharacter';
246      case _kMoveCursorBackwardByCharacterIndex:
247        return 'SemanticsAction.moveCursorBackwardByCharacter';
248      case _kSetSelectionIndex:
249        return 'SemanticsAction.setSelection';
250      case _kCopyIndex:
251        return 'SemanticsAction.copy';
252      case _kCutIndex:
253        return 'SemanticsAction.cut';
254      case _kPasteIndex:
255        return 'SemanticsAction.paste';
256      case _kDidGainAccessibilityFocusIndex:
257        return 'SemanticsAction.didGainAccessibilityFocus';
258      case _kDidLoseAccessibilityFocusIndex:
259        return 'SemanticsAction.didLoseAccessibilityFocus';
260      case _kCustomAction:
261        return 'SemanticsAction.customAction';
262      case _kDismissIndex:
263        return 'SemanticsAction.dismiss';
264      case _kMoveCursorForwardByWordIndex:
265        return 'SemanticsAction.moveCursorForwardByWord';
266      case _kMoveCursorBackwardByWordIndex:
267        return 'SemanticsAction.moveCursorBackwardByWord';
268    }
269    return null;
270  }
271}
272
273/// A Boolean value that can be associated with a semantics node.
274class SemanticsFlag {
275  static const int _kHasCheckedStateIndex = 1 << 0;
276  static const int _kIsCheckedIndex = 1 << 1;
277  static const int _kIsSelectedIndex = 1 << 2;
278  static const int _kIsButtonIndex = 1 << 3;
279  static const int _kIsTextFieldIndex = 1 << 4;
280  static const int _kIsFocusedIndex = 1 << 5;
281  static const int _kHasEnabledStateIndex = 1 << 6;
282  static const int _kIsEnabledIndex = 1 << 7;
283  static const int _kIsInMutuallyExclusiveGroupIndex = 1 << 8;
284  static const int _kIsHeaderIndex = 1 << 9;
285  static const int _kIsObscuredIndex = 1 << 10;
286  static const int _kScopesRouteIndex = 1 << 11;
287  static const int _kNamesRouteIndex = 1 << 12;
288  static const int _kIsHiddenIndex = 1 << 13;
289  static const int _kIsImageIndex = 1 << 14;
290  static const int _kIsLiveRegionIndex = 1 << 15;
291  static const int _kHasToggledStateIndex = 1 << 16;
292  static const int _kIsToggledIndex = 1 << 17;
293  static const int _kHasImplicitScrollingIndex = 1 << 18;
294  static const int _kIsMultilineIndex = 1 << 19;
295  static const int _kIsReadOnlyIndex = 1 << 20;
296
297  const SemanticsFlag._(this.index);
298
299  /// The numerical value for this flag.
300  ///
301  /// Each flag has one bit set in this bit field.
302  final int index;
303
304  /// The semantics node has the quality of either being "checked" or "unchecked".
305  ///
306  /// This flag is mutually exclusive with [hasToggledState].
307  ///
308  /// For example, a checkbox or a radio button widget has checked state.
309  ///
310  /// See also:
311  ///
312  ///   * [SemanticsFlag.isChecked], which controls whether the node is "checked" or "unchecked".
313  static const SemanticsFlag hasCheckedState =
314      SemanticsFlag._(_kHasCheckedStateIndex);
315
316  /// Whether a semantics node that [hasCheckedState] is checked.
317  ///
318  /// If true, the semantics node is "checked". If false, the semantics node is
319  /// "unchecked".
320  ///
321  /// For example, if a checkbox has a visible checkmark, [isChecked] is true.
322  ///
323  /// See also:
324  ///
325  ///   * [SemanticsFlag.hasCheckedState], which enables a checked state.
326  static const SemanticsFlag isChecked = SemanticsFlag._(_kIsCheckedIndex);
327
328  /// Whether a semantics node is selected.
329  ///
330  /// If true, the semantics node is "selected". If false, the semantics node is
331  /// "unselected".
332  ///
333  /// For example, the active tab in a tab bar has [isSelected] set to true.
334  static const SemanticsFlag isSelected = SemanticsFlag._(_kIsSelectedIndex);
335
336  /// Whether the semantic node represents a button.
337  ///
338  /// Platforms has special handling for buttons, for example Android's TalkBack
339  /// and iOS's VoiceOver provides an additional hint when the focused object is
340  /// a button.
341  static const SemanticsFlag isButton = SemanticsFlag._(_kIsButtonIndex);
342
343  /// Whether the semantic node represents a text field.
344  ///
345  /// Text fields are announced as such and allow text input via accessibility
346  /// affordances.
347  static const SemanticsFlag isTextField = SemanticsFlag._(_kIsTextFieldIndex);
348
349  /// Whether the semantic node currently holds the user's focus.
350  ///
351  /// The focused element is usually the current receiver of keyboard inputs.
352  static const SemanticsFlag isFocused = SemanticsFlag._(_kIsFocusedIndex);
353
354  /// The semantics node has the quality of either being "enabled" or
355  /// "disabled".
356  ///
357  /// For example, a button can be enabled or disabled and therefore has an
358  /// "enabled" state. Static text is usually neither enabled nor disabled and
359  /// therefore does not have an "enabled" state.
360  static const SemanticsFlag hasEnabledState =
361      SemanticsFlag._(_kHasEnabledStateIndex);
362
363  /// Whether the semantic node is read only.
364  ///
365  /// Only applicable when [isTextField] is true.
366  static const SemanticsFlag isReadOnly =
367      const SemanticsFlag._(_kIsReadOnlyIndex);
368
369  /// Whether a semantic node that [hasEnabledState] is currently enabled.
370  ///
371  /// A disabled element does not respond to user interaction. For example, a
372  /// button that currently does not respond to user interaction should be
373  /// marked as disabled.
374  static const SemanticsFlag isEnabled = SemanticsFlag._(_kIsEnabledIndex);
375
376  /// Whether a semantic node is in a mutually exclusive group.
377  ///
378  /// For example, a radio button is in a mutually exclusive group because
379  /// only one radio button in that group can be marked as [isChecked].
380  static const SemanticsFlag isInMutuallyExclusiveGroup =
381      SemanticsFlag._(_kIsInMutuallyExclusiveGroupIndex);
382
383  /// Whether a semantic node is a header that divides content into sections.
384  ///
385  /// For example, headers can be used to divide a list of alphabetically
386  /// sorted words into the sections A, B, C, etc. as can be found in many
387  /// address book applications.
388  static const SemanticsFlag isHeader = SemanticsFlag._(_kIsHeaderIndex);
389
390  /// Whether the value of the semantics node is obscured.
391  ///
392  /// This is usually used for text fields to indicate that its content
393  /// is a password or contains other sensitive information.
394  static const SemanticsFlag isObscured = SemanticsFlag._(_kIsObscuredIndex);
395
396  /// Whether the semantics node is the root of a subtree for which a route name
397  /// should be announced.
398  ///
399  /// When a node with this flag is removed from the semantics tree, the
400  /// framework will select the last in depth-first, paint order node with this
401  /// flag.  When a node with this flag is added to the semantics tree, it is
402  /// selected automatically, unless there were multiple nodes with this flag
403  /// added.  In this case, the last added node in depth-first, paint order
404  /// will be selected.
405  ///
406  /// From this selected node, the framework will search in depth-first, paint
407  /// order for the first node with a [namesRoute] flag and a non-null,
408  /// non-empty label. The [namesRoute] and [scopesRoute] flags may be on the
409  /// same node. The label of the found node will be announced as an edge
410  /// transition. If no non-empty, non-null label is found then:
411  ///
412  ///   * VoiceOver will make a chime announcement.
413  ///   * TalkBack will make no announcement
414  ///
415  /// Semantic nodes annotated with this flag are generally not a11y focusable.
416  ///
417  /// This is used in widgets such as Routes, Drawers, and Dialogs to
418  /// communicate significant changes in the visible screen.
419  static const SemanticsFlag scopesRoute = SemanticsFlag._(_kScopesRouteIndex);
420
421  /// Whether the semantics node label is the name of a visually distinct
422  /// route.
423  ///
424  /// This is used by certain widgets like Drawers and Dialogs, to indicate
425  /// that the node's semantic label can be used to announce an edge triggered
426  /// semantics update.
427  ///
428  /// Semantic nodes annotated with this flag will still recieve a11y focus.
429  ///
430  /// Updating this label within the same active route subtree will not cause
431  /// additional announcements.
432  static const SemanticsFlag namesRoute = SemanticsFlag._(_kNamesRouteIndex);
433
434  /// Whether the semantics node is considered hidden.
435  ///
436  /// Hidden elements are currently not visible on screen. They may be covered
437  /// by other elements or positioned outside of the visible area of a viewport.
438  ///
439  /// Hidden elements cannot gain accessibility focus though regular touch. The
440  /// only way they can be focused is by moving the focus to them via linear
441  /// navigation.
442  ///
443  /// Platforms are free to completely ignore hidden elements and new platforms
444  /// are encouraged to do so.
445  ///
446  /// Instead of marking an element as hidden it should usually be excluded from
447  /// the semantics tree altogether. Hidden elements are only included in the
448  /// semantics tree to work around platform limitations and they are mainly
449  /// used to implement accessibility scrolling on iOS.
450  static const SemanticsFlag isHidden = SemanticsFlag._(_kIsHiddenIndex);
451
452  /// Whether the semantics node represents an image.
453  ///
454  /// Both TalkBack and VoiceOver will inform the user the the semantics node
455  /// represents an image.
456  static const SemanticsFlag isImage = SemanticsFlag._(_kIsImageIndex);
457
458  /// Whether the semantics node is a live region.
459  ///
460  /// A live region indicates that updates to semantics node are important.
461  /// Platforms may use this information to make polite announcements to the
462  /// user to inform them of updates to this node.
463  ///
464  /// An example of a live region is a [SnackBar] widget. On Android, A live
465  /// region causes a polite announcement to be generated automatically, even
466  /// if the user does not have focus of the widget.
467  static const SemanticsFlag isLiveRegion =
468      SemanticsFlag._(_kIsLiveRegionIndex);
469
470  /// The semantics node has the quality of either being "on" or "off".
471  ///
472  /// This flag is mutually exclusive with [hasCheckedState].
473  ///
474  /// For example, a switch has toggled state.
475  ///
476  /// See also:
477  ///
478  ///    * [SemanticsFlag.isToggled], which controls whether the node is "on" or "off".
479  static const SemanticsFlag hasToggledState =
480      SemanticsFlag._(_kHasToggledStateIndex);
481
482  /// If true, the semantics node is "on". If false, the semantics node is
483  /// "off".
484  ///
485  /// For example, if a switch is in the on position, [isToggled] is true.
486  ///
487  /// See also:
488  ///
489  ///   * [SemanticsFlag.hasToggledState], which enables a toggled state.
490  static const SemanticsFlag isToggled = SemanticsFlag._(_kIsToggledIndex);
491
492  /// Whether the platform can scroll the semantics node when the user attempts
493  /// to move focus to an offscreen child.
494  ///
495  /// For example, a [ListView] widget has implicit scrolling so that users can
496  /// easily move to the next visible set of children. A [TabBar] widget does
497  /// not have implicit scrolling, so that users can navigate into the tab
498  /// body when reaching the end of the tab bar.
499  static const SemanticsFlag hasImplicitScrolling =
500      SemanticsFlag._(_kHasImplicitScrollingIndex);
501
502  /// Whether the value of the semantics node is coming from a multi-line text
503  /// field.
504  ///
505  /// This isused for text fields to distinguish single-line text field from
506  /// multi-line ones.
507  static const SemanticsFlag isMultiline = SemanticsFlag._(_kIsMultilineIndex);
508
509  /// The possible semantics flags.
510  ///
511  /// The map's key is the [index] of the flag and the value is the flag itself.
512  static const Map<int, SemanticsFlag> values = <int, SemanticsFlag>{
513    _kHasCheckedStateIndex: hasCheckedState,
514    _kIsCheckedIndex: isChecked,
515    _kIsSelectedIndex: isSelected,
516    _kIsButtonIndex: isButton,
517    _kIsTextFieldIndex: isTextField,
518    _kIsFocusedIndex: isFocused,
519    _kHasEnabledStateIndex: hasEnabledState,
520    _kIsEnabledIndex: isEnabled,
521    _kIsInMutuallyExclusiveGroupIndex: isInMutuallyExclusiveGroup,
522    _kIsHeaderIndex: isHeader,
523    _kIsObscuredIndex: isObscured,
524    _kScopesRouteIndex: scopesRoute,
525    _kNamesRouteIndex: namesRoute,
526    _kIsHiddenIndex: isHidden,
527    _kIsImageIndex: isImage,
528    _kIsLiveRegionIndex: isLiveRegion,
529    _kHasToggledStateIndex: hasToggledState,
530    _kIsToggledIndex: isToggled,
531    _kHasImplicitScrollingIndex: hasImplicitScrolling,
532    _kIsMultilineIndex: isMultiline,
533  };
534
535  @override
536  String toString() {
537    switch (index) {
538      case _kHasCheckedStateIndex:
539        return 'SemanticsFlag.hasCheckedState';
540      case _kIsCheckedIndex:
541        return 'SemanticsFlag.isChecked';
542      case _kIsSelectedIndex:
543        return 'SemanticsFlag.isSelected';
544      case _kIsButtonIndex:
545        return 'SemanticsFlag.isButton';
546      case _kIsTextFieldIndex:
547        return 'SemanticsFlag.isTextField';
548      case _kIsFocusedIndex:
549        return 'SemanticsFlag.isFocused';
550      case _kHasEnabledStateIndex:
551        return 'SemanticsFlag.hasEnabledState';
552      case _kIsEnabledIndex:
553        return 'SemanticsFlag.isEnabled';
554      case _kIsInMutuallyExclusiveGroupIndex:
555        return 'SemanticsFlag.isInMutuallyExclusiveGroup';
556      case _kIsHeaderIndex:
557        return 'SemanticsFlag.isHeader';
558      case _kIsObscuredIndex:
559        return 'SemanticsFlag.isObscured';
560      case _kScopesRouteIndex:
561        return 'SemanticsFlag.scopesRoute';
562      case _kNamesRouteIndex:
563        return 'SemanticsFlag.namesRoute';
564      case _kIsHiddenIndex:
565        return 'SemanticsFlag.isHidden';
566      case _kIsImageIndex:
567        return 'SemanticsFlag.isImage';
568      case _kIsLiveRegionIndex:
569        return 'SemanticsFlag.isLiveRegion';
570      case _kHasToggledStateIndex:
571        return 'SemanticsFlag.hasToggledState';
572      case _kIsToggledIndex:
573        return 'SemanticsFlag.isToggled';
574      case _kHasImplicitScrollingIndex:
575        return 'SemanticsFlag.hasImplicitScrolling';
576      case _kIsMultilineIndex:
577        return 'SemanticsFlag.isMultiline';
578    }
579    return null;
580  }
581}
582
583/// An object that creates [SemanticsUpdate] objects.
584///
585/// Once created, the [SemanticsUpdate] objects can be passed to
586/// [Window.updateSemantics] to update the semantics conveyed to the user.
587class SemanticsUpdateBuilder {
588  /// Creates an empty [SemanticsUpdateBuilder] object.
589  SemanticsUpdateBuilder();
590
591  final List<engine.SemanticsNodeUpdate> _nodeUpdates =
592      <engine.SemanticsNodeUpdate>[];
593
594  /// Update the information associated with the node with the given `id`.
595  ///
596  /// The semantics nodes form a tree, with the root of the tree always having
597  /// an id of zero. The `childrenInTraversalOrder` and `childrenInHitTestOrder`
598  /// are the ids of the nodes that are immediate children of this node. The
599  /// former enumerates children in traversal order, and the latter enumerates
600  /// the same children in the hit test order. The two lists must have the same
601  /// length and contain the same ids. They may only differ in the order the
602  /// ids are listed in. For more information about different child orders, see
603  /// [DebugSemanticsDumpOrder].
604  ///
605  /// The system retains the nodes that are currently reachable from the root.
606  /// A given update need not contain information for nodes that do not change
607  /// in the update. If a node is not reachable from the root after an update,
608  /// the node will be discarded from the tree.
609  ///
610  /// The `flags` are a bit field of [SemanticsFlag]s that apply to this node.
611  ///
612  /// The `actions` are a bit field of [SemanticsAction]s that can be undertaken
613  /// by this node. If the user wishes to undertake one of these actions on this
614  /// node, the [Window.onSemanticsAction] will be called with `id` and one of
615  /// the possible [SemanticsAction]s. Because the semantics tree is maintained
616  /// asynchronously, the [Window.onSemanticsAction] callback might be called
617  /// with an action that is no longer possible.
618  ///
619  /// The `label` is a string that describes this node. The `value` property
620  /// describes the current value of the node as a string. The `increasedValue`
621  /// string will become the `value` string after a [SemanticsAction.increase]
622  /// action is performed. The `decreasedValue` string will become the `value`
623  /// string after a [SemanticsAction.decrease] action is performed. The `hint`
624  /// string describes what result an action performed on this node has. The
625  /// reading direction of all these strings is given by `textDirection`.
626  ///
627  /// The fields 'textSelectionBase' and 'textSelectionExtent' describe the
628  /// currently selected text within `value`.
629  ///
630  /// For scrollable nodes `scrollPosition` describes the current scroll
631  /// position in logical pixel. `scrollExtentMax` and `scrollExtentMin`
632  /// describe the maximum and minimum in-rage values that `scrollPosition` can
633  /// be. Both or either may be infinity to indicate unbound scrolling. The
634  /// value for `scrollPosition` can (temporarily) be outside this range, for
635  /// example during an overscroll.
636  ///
637  /// The `rect` is the region occupied by this node in its own coordinate
638  /// system.
639  ///
640  /// The `transform` is a matrix that maps this node's coordinate system into
641  /// its parent's coordinate system.
642  void updateNode({
643    int id,
644    int flags,
645    int actions,
646    int textSelectionBase,
647    int textSelectionExtent,
648    int platformViewId,
649    int scrollChildren,
650    int scrollIndex,
651    double scrollPosition,
652    double scrollExtentMax,
653    double scrollExtentMin,
654    double elevation,
655    double thickness,
656    Rect rect,
657    String label,
658    String hint,
659    String value,
660    String increasedValue,
661    String decreasedValue,
662    TextDirection textDirection,
663    Float64List transform,
664    Int32List childrenInTraversalOrder,
665    Int32List childrenInHitTestOrder,
666    Int32List additionalActions,
667  }) {
668    if (transform.length != 16)
669      throw ArgumentError('transform argument must have 16 entries.');
670    _nodeUpdates.add(engine.SemanticsNodeUpdate(
671      id: id,
672      flags: flags,
673      actions: actions,
674      textSelectionBase: textSelectionBase,
675      textSelectionExtent: textSelectionExtent,
676      scrollChildren: scrollChildren,
677      scrollIndex: scrollIndex,
678      scrollPosition: scrollPosition,
679      scrollExtentMax: scrollExtentMax,
680      scrollExtentMin: scrollExtentMin,
681      rect: rect,
682      label: label,
683      hint: hint,
684      value: value,
685      increasedValue: increasedValue,
686      decreasedValue: decreasedValue,
687      textDirection: textDirection,
688      transform: transform,
689      elevation: elevation,
690      thickness: thickness,
691      childrenInTraversalOrder: childrenInTraversalOrder,
692      childrenInHitTestOrder: childrenInHitTestOrder,
693      additionalActions: additionalActions,
694      platformViewId: platformViewId,
695    ));
696  }
697
698  void updateCustomAction(
699      {int id, String label, String hint, int overrideId = -1}) {
700    // TODO(yjbanov): implement.
701  }
702
703  /// Creates a [SemanticsUpdate] object that encapsulates the updates recorded
704  /// by this object.
705  ///
706  /// The returned object can be passed to [Window.updateSemantics] to actually
707  /// update the semantics retained by the system.
708  SemanticsUpdate build() {
709    return SemanticsUpdate._(
710      nodeUpdates: _nodeUpdates,
711    );
712  }
713}
714
715/// An opaque object representing a batch of semantics updates.
716///
717/// To create a SemanticsUpdate object, use a [SemanticsUpdateBuilder].
718///
719/// Semantics updates can be applied to the system's retained semantics tree
720/// using the [Window.updateSemantics] method.
721abstract class SemanticsUpdate {
722  /// This class is created by the engine, and should not be instantiated
723  /// or extended directly.
724  ///
725  /// To create a SemanticsUpdate object, use a [SemanticsUpdateBuilder].
726  factory SemanticsUpdate._({List<engine.SemanticsNodeUpdate> nodeUpdates}) =
727      engine.SemanticsUpdate;
728
729  /// Releases the resources used by this semantics update.
730  ///
731  /// After calling this function, the semantics update is cannot be used
732  /// further.
733  void dispose();
734}
735