Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
55c7e6e3
Unverified
Commit
55c7e6e3
authored
Aug 02, 2018
by
Jonah Williams
Committed by
GitHub
Aug 02, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support customizing standard accessibility action hints on Android. (#19665)
parent
651c5ab3
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
328 additions
and
14 deletions
+328
-14
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+14
-0
semantics.dart
packages/flutter/lib/src/semantics/semantics.dart
+157
-10
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+9
-0
semantics_test.dart
packages/flutter/test/widgets/semantics_test.dart
+45
-0
matchers.dart
packages/flutter_test/lib/src/matchers.dart
+43
-3
matchers_test.dart
packages/flutter_test/test/matchers_test.dart
+60
-1
No files found.
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
55c7e6e3
...
...
@@ -3207,6 +3207,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
String
increasedValue
,
String
decreasedValue
,
String
hint
,
SemanticsHintOverrides
hintOverrides
,
TextDirection
textDirection
,
SemanticsSortKey
sortKey
,
VoidCallback
onTap
,
...
...
@@ -3252,6 +3253,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
_increasedValue
=
increasedValue
,
_decreasedValue
=
decreasedValue
,
_hint
=
hint
,
_hintOverrides
=
hintOverrides
,
_textDirection
=
textDirection
,
_sortKey
=
sortKey
,
_onTap
=
onTap
,
...
...
@@ -3548,6 +3550,16 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
markNeedsSemanticsUpdate
();
}
/// If non-null, sets the [SemanticsNode.hintOverride] to the given value.
SemanticsHintOverrides
get
hintOverrides
=>
_hintOverrides
;
SemanticsHintOverrides
_hintOverrides
;
set
hintOverrides
(
SemanticsHintOverrides
value
)
{
if
(
_hintOverrides
==
value
)
return
;
_hintOverrides
=
value
;
markNeedsSemanticsUpdate
();
}
/// If non-null, sets the [SemanticsNode.textDirection] semantic to the given value.
///
/// This must not be null if [label], [hint], [value], [increasedValue], or
...
...
@@ -3989,6 +4001,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
config
.
decreasedValue
=
decreasedValue
;
if
(
hint
!=
null
)
config
.
hint
=
hint
;
if
(
hintOverrides
!=
null
&&
hintOverrides
.
isNotEmpty
)
config
.
hintOverrides
=
hintOverrides
;
if
(
scopesRoute
!=
null
)
config
.
scopesRoute
=
scopesRoute
;
if
(
namesRoute
!=
null
)
...
...
packages/flutter/lib/src/semantics/semantics.dart
View file @
55c7e6e3
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/basic.dart
View file @
55c7e6e3
...
...
@@ -5098,6 +5098,8 @@ class Semantics extends SingleChildRenderObjectWidget {
String
increasedValue
,
String
decreasedValue
,
String
hint
,
String
onTapHint
,
String
onLongPressHint
,
TextDirection
textDirection
,
SemanticsSortKey
sortKey
,
VoidCallback
onTap
,
...
...
@@ -5165,6 +5167,11 @@ class Semantics extends SingleChildRenderObjectWidget {
onDismiss:
onDismiss
,
onSetSelection:
onSetSelection
,
customSemanticsActions:
customSemanticsActions
,
hintOverrides:
onTapHint
!=
null
||
onLongPressHint
!=
null
?
new
SemanticsHintOverrides
(
onTapHint:
onTapHint
,
onLongPressHint:
onLongPressHint
,
)
:
null
,
),
);
...
...
@@ -5248,6 +5255,7 @@ class Semantics extends SingleChildRenderObjectWidget {
increasedValue:
properties
.
increasedValue
,
decreasedValue:
properties
.
decreasedValue
,
hint:
properties
.
hint
,
hintOverrides:
properties
.
hintOverrides
,
textDirection:
_getTextDirection
(
context
),
sortKey:
properties
.
sortKey
,
onTap:
properties
.
onTap
,
...
...
@@ -5308,6 +5316,7 @@ class Semantics extends SingleChildRenderObjectWidget {
..
increasedValue
=
properties
.
increasedValue
..
decreasedValue
=
properties
.
decreasedValue
..
hint
=
properties
.
hint
..
hintOverrides
=
properties
.
hintOverrides
..
namesRoute
=
properties
.
namesRoute
..
textDirection
=
_getTextDirection
(
context
)
..
sortKey
=
properties
.
sortKey
...
...
packages/flutter/test/widgets/semantics_test.dart
View file @
55c7e6e3
...
...
@@ -634,6 +634,51 @@ void main() {
semantics
.
dispose
();
});
testWidgets
(
'onTapHint and onLongPressHint create custom actions'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semantics
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
new
Semantics
(
container:
true
,
onTap:
()
{},
onTapHint:
'test'
,
));
expect
(
tester
.
getSemanticsData
(
find
.
byType
(
Semantics
)),
matchesSemanticsData
(
hasTapAction:
true
,
onTapHint:
'test'
));
await
tester
.
pumpWidget
(
new
Semantics
(
container:
true
,
onLongPress:
()
{},
onLongPressHint:
'foo'
,
));
expect
(
tester
.
getSemanticsData
(
find
.
byType
(
Semantics
)),
matchesSemanticsData
(
hasLongPressAction:
true
,
onLongPressHint:
'foo'
));
semantics
.
dispose
();
});
testWidgets
(
'CustomSemanticsActions can be added to a Semantics widget'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semantics
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
new
Semantics
(
container:
true
,
customSemanticsActions:
<
CustomSemanticsAction
,
VoidCallback
>{
const
CustomSemanticsAction
(
label:
'foo'
):
()
{},
const
CustomSemanticsAction
(
label:
'bar'
):
()
{}
},
));
expect
(
tester
.
getSemanticsData
(
find
.
byType
(
Semantics
)),
matchesSemanticsData
(
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'bar'
),
const
CustomSemanticsAction
(
label:
'foo'
),
],
));
semantics
.
dispose
();
});
testWidgets
(
'Increased/decreased values are annotated'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
new
SemanticsTester
(
tester
);
...
...
packages/flutter_test/lib/src/matchers.dart
View file @
55c7e6e3
...
...
@@ -345,8 +345,11 @@ Matcher matchesSemanticsData({
bool
hasPasteAction
=
false
,
bool
hasDidGainAccessibilityFocusAction
=
false
,
bool
hasDidLoseAccessibilityFocusAction
=
false
,
bool
hasCustomAction
=
false
,
bool
hasDismissAction
=
false
,
// Custom actions and overrides
String
onTapHint
,
String
onLongPressHint
,
List
<
CustomSemanticsAction
>
customActions
,
})
{
final
List
<
SemanticsFlag
>
flags
=
<
SemanticsFlag
>[];
if
(
hasCheckedState
)
...
...
@@ -421,7 +424,7 @@ Matcher matchesSemanticsData({
actions
.
add
(
SemanticsAction
.
didGainAccessibilityFocus
);
if
(
hasDidLoseAccessibilityFocusAction
)
actions
.
add
(
SemanticsAction
.
didLoseAccessibilityFocus
);
if
(
hasCustomAction
)
if
(
customActions
!=
null
&&
customActions
.
isNotEmpty
)
actions
.
add
(
SemanticsAction
.
customAction
);
if
(
hasDismissAction
)
actions
.
add
(
SemanticsAction
.
dismiss
);
...
...
@@ -429,6 +432,12 @@ Matcher matchesSemanticsData({
actions
.
add
(
SemanticsAction
.
moveCursorForwardByWord
);
if
(
hasMoveCursorBackwardByWordAction
)
actions
.
add
(
SemanticsAction
.
moveCursorBackwardByWord
);
SemanticsHintOverrides
hintOverrides
;
if
(
onTapHint
!=
null
||
onLongPressHint
!=
null
)
hintOverrides
=
new
SemanticsHintOverrides
(
onTapHint:
onTapHint
,
onLongPressHint:
onLongPressHint
,
);
return
new
_MatchesSemanticsData
(
label:
label
,
...
...
@@ -438,6 +447,8 @@ Matcher matchesSemanticsData({
flags:
flags
,
textDirection:
textDirection
,
rect:
rect
,
customActions:
customActions
,
hintOverrides:
hintOverrides
,
);
}
...
...
@@ -1467,12 +1478,16 @@ class _MatchesSemanticsData extends Matcher {
this
.
actions
,
this
.
textDirection
,
this
.
rect
,
this
.
customActions
,
this
.
hintOverrides
,
});
final
String
label
;
final
String
value
;
final
String
hint
;
final
SemanticsHintOverrides
hintOverrides
;
final
List
<
SemanticsAction
>
actions
;
final
List
<
CustomSemanticsAction
>
customActions
;
final
List
<
SemanticsFlag
>
flags
;
final
TextDirection
textDirection
;
final
Rect
rect
;
...
...
@@ -1494,6 +1509,10 @@ class _MatchesSemanticsData extends Matcher {
description
.
add
(
'with textDirection:
$textDirection
'
);
if
(
rect
!=
null
)
description
.
add
(
'with rect:
$rect
'
);
if
(
customActions
!=
null
)
description
.
add
(
'with custom actions:
$customActions
'
);
if
(
hintOverrides
!=
null
)
description
.
add
(
'with custom hints:
$hintOverrides
'
);
return
description
;
}
...
...
@@ -1511,7 +1530,7 @@ class _MatchesSemanticsData extends Matcher {
return
failWithDescription
(
matchState
,
'value was:
${data.value}
'
);
if
(
textDirection
!=
null
&&
textDirection
!=
data
.
textDirection
)
return
failWithDescription
(
matchState
,
'textDirection was:
$textDirection
'
);
if
(
rect
!=
null
&&
rect
=
=
data
.
rect
)
{
if
(
rect
!=
null
&&
rect
!
=
data
.
rect
)
{
return
failWithDescription
(
matchState
,
'rect was:
$rect
'
);
}
if
(
actions
!=
null
)
{
...
...
@@ -1527,6 +1546,27 @@ class _MatchesSemanticsData extends Matcher {
return
failWithDescription
(
matchState
,
'actions were:
$actionSummary
'
);
}
}
if
(
customActions
!=
null
||
hintOverrides
!=
null
)
{
final
List
<
CustomSemanticsAction
>
providedCustomActions
=
data
.
customSemanticsActionIds
.
map
((
int
id
)
{
return
CustomSemanticsAction
.
getAction
(
id
);
}).
toList
();
final
List
<
CustomSemanticsAction
>
expectedCustomActions
=
new
List
<
CustomSemanticsAction
>.
from
(
customActions
??
const
<
int
>[]);
if
(
hintOverrides
?.
onTapHint
!=
null
)
expectedCustomActions
.
add
(
new
CustomSemanticsAction
.
overridingAction
(
hint:
hintOverrides
.
onTapHint
,
action:
SemanticsAction
.
tap
));
if
(
hintOverrides
?.
onLongPressHint
!=
null
)
expectedCustomActions
.
add
(
new
CustomSemanticsAction
.
overridingAction
(
hint:
hintOverrides
.
onLongPressHint
,
action:
SemanticsAction
.
longPress
));
if
(
expectedCustomActions
.
length
!=
providedCustomActions
.
length
)
return
failWithDescription
(
matchState
,
'custom actions where:
$providedCustomActions
'
);
int
sortActions
(
CustomSemanticsAction
left
,
CustomSemanticsAction
right
)
{
return
CustomSemanticsAction
.
getIdentifier
(
left
)
-
CustomSemanticsAction
.
getIdentifier
(
right
);
}
expectedCustomActions
.
sort
(
sortActions
);
providedCustomActions
.
sort
(
sortActions
);
for
(
int
i
=
0
;
i
<
expectedCustomActions
.
length
;
i
++)
{
if
(
expectedCustomActions
[
i
]
!=
providedCustomActions
[
i
])
return
failWithDescription
(
matchState
,
'custom actions where:
$providedCustomActions
'
);
}
}
if
(
flags
!=
null
)
{
int
flagBits
=
0
;
for
(
SemanticsFlag
flag
in
flags
)
...
...
packages/flutter_test/test/matchers_test.dart
View file @
55c7e6e3
...
...
@@ -394,10 +394,17 @@ void main() {
header:
true
,
button:
true
,
onTap:
()
{},
onLongPress:
()
{},
label:
'foo'
,
hint:
'bar'
,
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
onTapHint:
'scan'
,
onLongPressHint:
'fill'
,
customSemanticsActions:
<
CustomSemanticsAction
,
VoidCallback
>{
const
CustomSemanticsAction
(
label:
'foo'
):
()
{},
const
CustomSemanticsAction
(
label:
'bar'
):
()
{},
},
));
expect
(
tester
.
getSemanticsData
(
find
.
byKey
(
key
)),
...
...
@@ -407,17 +414,68 @@ void main() {
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
hasTapAction:
true
,
hasLongPressAction:
true
,
isButton:
true
,
isHeader:
true
,
namesRoute:
true
,
onTapHint:
'scan'
,
onLongPressHint:
'fill'
,
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'foo'
),
const
CustomSemanticsAction
(
label:
'bar'
)
],
),
);
// Doesn't match custom actions
expect
(
tester
.
getSemanticsData
(
find
.
byKey
(
key
)),
isNot
(
matchesSemanticsData
(
label:
'foo'
,
hint:
'bar'
,
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
hasTapAction:
true
,
hasLongPressAction:
true
,
isButton:
true
,
isHeader:
true
,
namesRoute:
true
,
onTapHint:
'scan'
,
onLongPressHint:
'fill'
,
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'foo'
),
const
CustomSemanticsAction
(
label:
'barz'
)
],
)),
);
// Doesn't match wrong hints
expect
(
tester
.
getSemanticsData
(
find
.
byKey
(
key
)),
isNot
(
matchesSemanticsData
(
label:
'foo'
,
hint:
'bar'
,
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
hasTapAction:
true
,
hasLongPressAction:
true
,
isButton:
true
,
isHeader:
true
,
namesRoute:
true
,
onTapHint:
'scans'
,
onLongPressHint:
'fills'
,
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'foo'
),
const
CustomSemanticsAction
(
label:
'bar'
)
],
)),
);
handle
.
dispose
();
});
testWidgets
(
'Can match all semantics flags and actions'
,
(
WidgetTester
tester
)
async
{
int
actions
=
0
;
int
flags
=
0
;
const
CustomSemanticsAction
action
=
const
CustomSemanticsAction
(
label:
'test'
);
for
(
int
index
in
SemanticsAction
.
values
.
keys
)
actions
|=
index
;
for
(
int
index
in
SemanticsFlag
.
values
.
keys
)
...
...
@@ -436,6 +494,7 @@ void main() {
scrollPosition:
null
,
scrollExtentMax:
null
,
scrollExtentMin:
null
,
customSemanticsActionIds:
<
int
>[
CustomSemanticsAction
.
getIdentifier
(
action
)],
);
expect
(
data
,
matchesSemanticsData
(
...
...
@@ -478,8 +537,8 @@ void main() {
hasPasteAction:
true
,
hasDidGainAccessibilityFocusAction:
true
,
hasDidLoseAccessibilityFocusAction:
true
,
hasCustomAction:
true
,
hasDismissAction:
true
,
customActions:
<
CustomSemanticsAction
>[
action
],
));
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment