mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Send nextId in addition to previousId for traversal order (#14676)
This commit is contained in:
parent
80c10bc431
commit
58689c796c
@ -1 +1 @@
|
||||
f5a4a9378740c3d5996583a9ed1f7e28ff08ee85
|
||||
36a9c343b7c5ec361b60c37d154071146daeeea7
|
||||
|
@ -92,6 +92,7 @@ class SemanticsData extends Diagnosticable {
|
||||
@required this.decreasedValue,
|
||||
@required this.hint,
|
||||
@required this.textDirection,
|
||||
@required this.nextNodeId,
|
||||
@required this.previousNodeId,
|
||||
@required this.rect,
|
||||
@required this.textSelection,
|
||||
@ -151,6 +152,10 @@ class SemanticsData extends Diagnosticable {
|
||||
/// [increasedValue], and [decreasedValue].
|
||||
final TextDirection textDirection;
|
||||
|
||||
/// The index indicating the ID of the next node in the traversal order after
|
||||
/// this node for the platform's accessibility services.
|
||||
final int nextNodeId;
|
||||
|
||||
/// The index indicating the ID of the previous node in the traversal order before
|
||||
/// this node for the platform's accessibility services.
|
||||
final int previousNodeId;
|
||||
@ -237,6 +242,7 @@ class SemanticsData extends Diagnosticable {
|
||||
properties.add(new StringProperty('decreasedValue', decreasedValue, defaultValue: ''));
|
||||
properties.add(new StringProperty('hint', hint, defaultValue: ''));
|
||||
properties.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
||||
properties.add(new IntProperty('nextNodeId', nextNodeId, defaultValue: null));
|
||||
properties.add(new IntProperty('previousNodeId', previousNodeId, defaultValue: null));
|
||||
if (textSelection?.isValid == true)
|
||||
properties.add(new MessageProperty('textSelection', '[${textSelection.start}, ${textSelection.end}]'));
|
||||
@ -258,6 +264,7 @@ class SemanticsData extends Diagnosticable {
|
||||
&& typedOther.decreasedValue == decreasedValue
|
||||
&& typedOther.hint == hint
|
||||
&& typedOther.textDirection == textDirection
|
||||
&& typedOther.nextNodeId == nextNodeId
|
||||
&& typedOther.previousNodeId == previousNodeId
|
||||
&& typedOther.rect == rect
|
||||
&& setEquals(typedOther.tags, tags)
|
||||
@ -269,7 +276,7 @@ class SemanticsData extends Diagnosticable {
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => ui.hashValues(flags, actions, label, value, increasedValue, decreasedValue, hint, textDirection, previousNodeId, rect, tags, textSelection, scrollPosition, scrollExtentMax, scrollExtentMin, transform);
|
||||
int get hashCode => ui.hashValues(flags, actions, label, value, increasedValue, decreasedValue, hint, textDirection, nextNodeId, previousNodeId, rect, tags, textSelection, scrollPosition, scrollExtentMax, scrollExtentMin, transform);
|
||||
}
|
||||
|
||||
class _SemanticsDiagnosticableNode extends DiagnosticableNode<SemanticsNode> {
|
||||
@ -1067,10 +1074,30 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
|
||||
/// The sort order for ordering the traversal of [SemanticsNode]s by the
|
||||
/// platform's accessibility services (e.g. VoiceOver on iOS and TalkBack on
|
||||
/// Android). This is used to determine the [previousNodeId] during a semantics update.
|
||||
/// Android). This is used to determine the [nextNodeId] and [previousNodeId]
|
||||
/// during a semantics update.
|
||||
SemanticsSortOrder _sortOrder;
|
||||
SemanticsSortOrder get sortOrder => _sortOrder;
|
||||
|
||||
/// The ID of the next node in the traversal order after this node.
|
||||
///
|
||||
/// Only valid after at least one semantics update has been built.
|
||||
///
|
||||
/// This is the value passed to the engine to tell it what the order
|
||||
/// should be for traversing semantics nodes.
|
||||
///
|
||||
/// If this is set to -1, it will indicate that there is no next node to
|
||||
/// the engine (i.e. this is the last node in the sort order). When it is
|
||||
/// null, it means that no semantics update has been built yet.
|
||||
int _nextNodeId;
|
||||
void _updateNextNodeId(int value) {
|
||||
if (value == _nextNodeId)
|
||||
return;
|
||||
_nextNodeId = value;
|
||||
_markDirty();
|
||||
}
|
||||
int get nextNodeId => _nextNodeId;
|
||||
|
||||
/// The ID of the previous node in the traversal order before this node.
|
||||
///
|
||||
/// Only valid after at least one semantics update has been built.
|
||||
@ -1194,6 +1221,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
String increasedValue = _increasedValue;
|
||||
String decreasedValue = _decreasedValue;
|
||||
TextDirection textDirection = _textDirection;
|
||||
int nextNodeId = _nextNodeId;
|
||||
int previousNodeId = _previousNodeId;
|
||||
Set<SemanticsTag> mergedTags = tags == null ? null : new Set<SemanticsTag>.from(tags);
|
||||
TextSelection textSelection = _textSelection;
|
||||
@ -1207,6 +1235,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
flags |= node._flags;
|
||||
actions |= node._actionsAsBits;
|
||||
textDirection ??= node._textDirection;
|
||||
nextNodeId ??= node._nextNodeId;
|
||||
previousNodeId ??= node._previousNodeId;
|
||||
textSelection ??= node._textSelection;
|
||||
scrollPosition ??= node._scrollPosition;
|
||||
@ -1247,6 +1276,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
decreasedValue: decreasedValue,
|
||||
hint: hint,
|
||||
textDirection: textDirection,
|
||||
nextNodeId: nextNodeId,
|
||||
previousNodeId: previousNodeId,
|
||||
rect: rect,
|
||||
transform: transform,
|
||||
@ -1289,6 +1319,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
increasedValue: data.increasedValue,
|
||||
hint: data.hint,
|
||||
textDirection: data.textDirection,
|
||||
nextNodeId: data.nextNodeId,
|
||||
previousNodeId: data.previousNodeId,
|
||||
textSelectionBase: data.textSelection != null ? data.textSelection.baseOffset : -1,
|
||||
textSelectionExtent: data.textSelection != null ? data.textSelection.extentOffset : -1,
|
||||
@ -1363,6 +1394,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
properties.add(new StringProperty('decreasedValue', _decreasedValue, defaultValue: ''));
|
||||
properties.add(new StringProperty('hint', _hint, defaultValue: ''));
|
||||
properties.add(new EnumProperty<TextDirection>('textDirection', _textDirection, defaultValue: null));
|
||||
properties.add(new IntProperty('nextNodeId', _nextNodeId, defaultValue: null));
|
||||
properties.add(new IntProperty('previousNodeId', _previousNodeId, defaultValue: null));
|
||||
properties.add(new DiagnosticsProperty<SemanticsSortOrder>('sortOrder', sortOrder, defaultValue: null));
|
||||
if (_textSelection?.isValid == true)
|
||||
@ -1539,10 +1571,10 @@ class SemanticsOwner extends ChangeNotifier {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Updates the previousNodeId IDs on the semantics nodes. These IDs are used
|
||||
// on the platform side to order the nodes for traversal by the accessibility
|
||||
// services. If the previousNodeId for a node changes, the node will be marked as
|
||||
// dirty.
|
||||
// Updates the nextNodeId and previousNodeId IDs on the semantics nodes. These
|
||||
// IDs are used on the platform side to order the nodes for traversal by the
|
||||
// accessibility services. If the nextNodeId or previousNodeId for a node
|
||||
// changes, the node will be marked as dirty.
|
||||
void _updateTraversalOrder() {
|
||||
final List<_TraversalSortNode> nodesInSemanticsTraversalOrder = <_TraversalSortNode>[];
|
||||
SemanticsSortOrder currentSortOrder = new SemanticsSortOrder(keys: <SemanticsSortKey>[]);
|
||||
@ -1577,12 +1609,20 @@ class SemanticsOwner extends ChangeNotifier {
|
||||
return true;
|
||||
}
|
||||
rootSemanticsNode.visitChildren(visitor);
|
||||
|
||||
if (nodesInSemanticsTraversalOrder.isEmpty)
|
||||
return;
|
||||
|
||||
nodesInSemanticsTraversalOrder.sort();
|
||||
int previousNodeId = -1;
|
||||
for (_TraversalSortNode node in nodesInSemanticsTraversalOrder) {
|
||||
node.node._updatePreviousNodeId(previousNodeId);
|
||||
previousNodeId = node.node.id;
|
||||
_TraversalSortNode node = nodesInSemanticsTraversalOrder.removeLast();
|
||||
node.node._updateNextNodeId(-1);
|
||||
while (nodesInSemanticsTraversalOrder.isNotEmpty) {
|
||||
final _TraversalSortNode previousNode = nodesInSemanticsTraversalOrder.removeLast();
|
||||
node.node._updatePreviousNodeId(previousNode.node.id);
|
||||
previousNode.node._updateNextNodeId(node.node.id);
|
||||
node = previousNode;
|
||||
}
|
||||
node.node._updatePreviousNodeId(-1);
|
||||
}
|
||||
|
||||
/// Update the semantics using [Window.updateSemantics].
|
||||
|
@ -348,7 +348,7 @@ void main() {
|
||||
|
||||
expect(
|
||||
minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden),
|
||||
'SemanticsNode#1(owner: null, isMergedIntoParent: false, mergeAllDescendantsIntoThisNode: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isInMutuallyExcusiveGroup: false, isSelected: false, isFocused: false, isButton: false, isTextField: false, invisible, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null, previousNodeId: null, sortOrder: null, scrollExtentMin: null, scrollPosition: null, scrollExtentMax: null)\n'
|
||||
'SemanticsNode#1(owner: null, isMergedIntoParent: false, mergeAllDescendantsIntoThisNode: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isInMutuallyExcusiveGroup: false, isSelected: false, isFocused: false, isButton: false, isTextField: false, invisible, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null, nextNodeId: null, previousNodeId: null, sortOrder: null, scrollExtentMin: null, scrollPosition: null, scrollExtentMax: null)\n'
|
||||
);
|
||||
|
||||
final SemanticsConfiguration config = new SemanticsConfiguration()
|
||||
|
@ -417,6 +417,7 @@ void main() {
|
||||
rect: TestSemantics.fullScreen,
|
||||
actions: allActions.fold(0, (int previous, SemanticsAction action) => previous | action.index),
|
||||
previousNodeId: -1,
|
||||
nextNodeId: -1,
|
||||
),
|
||||
],
|
||||
);
|
||||
@ -613,36 +614,51 @@ void main() {
|
||||
expect(semanticsUpdateCount, 1);
|
||||
expect(semantics, hasSemantics(
|
||||
new TestSemantics(
|
||||
id: 0,
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
id: 2,
|
||||
nextNodeId: 5,
|
||||
previousNodeId: -1,
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
id: 3,
|
||||
label: r'Label 1',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: -1,
|
||||
previousNodeId: 4,
|
||||
),
|
||||
new TestSemantics(
|
||||
id: 4,
|
||||
label: r'Label 2',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 3,
|
||||
previousNodeId: 6,
|
||||
),
|
||||
new TestSemantics(
|
||||
id: 5,
|
||||
nextNodeId: 8,
|
||||
previousNodeId: 2,
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
id: 6,
|
||||
label: r'Label 3',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 4,
|
||||
previousNodeId: 7,
|
||||
),
|
||||
new TestSemantics(
|
||||
id: 7,
|
||||
label: r'Label 4',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 6,
|
||||
previousNodeId: 8,
|
||||
),
|
||||
new TestSemantics(
|
||||
id: 8,
|
||||
label: r'Label 5',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 7,
|
||||
previousNodeId: 5,
|
||||
),
|
||||
],
|
||||
@ -650,7 +666,7 @@ void main() {
|
||||
],
|
||||
),
|
||||
],
|
||||
), ignoreTransform: true, ignoreRect: true, ignoreId: true),
|
||||
), ignoreTransform: true, ignoreRect: true),
|
||||
);
|
||||
semantics.dispose();
|
||||
});
|
||||
@ -713,26 +729,31 @@ void main() {
|
||||
new TestSemantics(
|
||||
label: r'Label 1',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: -1,
|
||||
previousNodeId: 3,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 2',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 2,
|
||||
previousNodeId: 4,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 3',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 3,
|
||||
previousNodeId: 5,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 4',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 4,
|
||||
previousNodeId: 6,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 5',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 5,
|
||||
previousNodeId: -1,
|
||||
),
|
||||
],
|
||||
@ -802,31 +823,37 @@ void main() {
|
||||
new TestSemantics(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
nextNodeId: 5,
|
||||
previousNodeId: -1,
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
label: r'Label 1',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 7,
|
||||
previousNodeId: 5,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 2',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: -1,
|
||||
previousNodeId: 6,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 3',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 3,
|
||||
previousNodeId: 2,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 4',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 4,
|
||||
previousNodeId: 7,
|
||||
),
|
||||
new TestSemantics(
|
||||
label: r'Label 5',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 6,
|
||||
previousNodeId: 3,
|
||||
),
|
||||
],
|
||||
|
@ -43,6 +43,7 @@ class TestSemantics {
|
||||
this.decreasedValue: '',
|
||||
this.hint: '',
|
||||
this.textDirection,
|
||||
this.nextNodeId,
|
||||
this.previousNodeId,
|
||||
this.rect,
|
||||
this.transform,
|
||||
@ -71,6 +72,7 @@ class TestSemantics {
|
||||
this.hint: '',
|
||||
this.textDirection,
|
||||
this.previousNodeId,
|
||||
this.nextNodeId,
|
||||
this.transform,
|
||||
this.textSelection,
|
||||
this.children: const <TestSemantics>[],
|
||||
@ -106,6 +108,7 @@ class TestSemantics {
|
||||
this.increasedValue: '',
|
||||
this.decreasedValue: '',
|
||||
this.textDirection,
|
||||
this.nextNodeId,
|
||||
this.previousNodeId,
|
||||
this.rect,
|
||||
Matrix4 transform,
|
||||
@ -173,6 +176,10 @@ class TestSemantics {
|
||||
/// is also set.
|
||||
final TextDirection textDirection;
|
||||
|
||||
/// The ID of the node that is next in the semantics traversal order after
|
||||
/// this node.
|
||||
final int nextNodeId;
|
||||
|
||||
/// The ID of the node that is previous in the semantics traversal order before
|
||||
/// this node.
|
||||
final int previousNodeId;
|
||||
@ -258,6 +265,8 @@ class TestSemantics {
|
||||
return fail('expected node id $id to have hint "$hint" but found hint "${nodeData.hint}".');
|
||||
if (textDirection != null && textDirection != nodeData.textDirection)
|
||||
return fail('expected node id $id to have textDirection "$textDirection" but found "${nodeData.textDirection}".');
|
||||
if (nextNodeId != null && nextNodeId != nodeData.nextNodeId)
|
||||
return fail('expected node id $id to have nextNodeId "$nextNodeId" but found "${nodeData.nextNodeId}".');
|
||||
if (previousNodeId != null && previousNodeId != nodeData.previousNodeId)
|
||||
return fail('expected node id $id to have previousNodeId "$previousNodeId" but found "${nodeData.previousNodeId}".');
|
||||
if ((nodeData.label != '' || nodeData.value != '' || nodeData.hint != '' || node.increasedValue != '' || node.decreasedValue != '') && nodeData.textDirection == null)
|
||||
@ -311,6 +320,8 @@ class TestSemantics {
|
||||
buf.writeln('$indent hint: \'$hint\',');
|
||||
if (textDirection != null)
|
||||
buf.writeln('$indent textDirection: $textDirection,');
|
||||
if (nextNodeId != null)
|
||||
buf.writeln('$indent nextNodeId: $nextNodeId,');
|
||||
if (previousNodeId != null)
|
||||
buf.writeln('$indent previousNodeId: $previousNodeId,');
|
||||
if (textSelection?.isValid == true)
|
||||
@ -522,6 +533,8 @@ class SemanticsTester {
|
||||
buf.writeln(' hint: r\'${node.hint}\',');
|
||||
if (node.textDirection != null)
|
||||
buf.writeln(' textDirection: ${node.textDirection},');
|
||||
if (node.nextNodeId != null)
|
||||
buf.writeln(' nextNodeId: ${node.nextNodeId},');
|
||||
if (node.previousNodeId != null)
|
||||
buf.writeln(' previousNodeId: ${node.previousNodeId},');
|
||||
|
||||
|
@ -105,14 +105,17 @@ void _tests() {
|
||||
new TestSemantics(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
nextNodeId: 4,
|
||||
previousNodeId: -1,
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
nextNodeId: 2,
|
||||
previousNodeId: 1,
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
label: r'Plain text',
|
||||
textDirection: TextDirection.ltr,
|
||||
nextNodeId: 3,
|
||||
previousNodeId: 4,
|
||||
),
|
||||
new TestSemantics(
|
||||
@ -124,6 +127,7 @@ void _tests() {
|
||||
decreasedValue: r'test-decreasedValue',
|
||||
hint: r'test-hint',
|
||||
textDirection: TextDirection.rtl,
|
||||
nextNodeId: -1,
|
||||
previousNodeId: 2,
|
||||
),
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user