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
1002a768
Unverified
Commit
1002a768
authored
Sep 21, 2021
by
Darren Austin
Committed by
GitHub
Sep 21, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reland "Migrate android_semantics_testing to null safety" (#90466)
parent
27952cc4
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
91 additions
and
84 deletions
+91
-84
main.dart
...integration_tests/android_semantics_testing/lib/main.dart
+6
-6
common.dart
...ation_tests/android_semantics_testing/lib/src/common.dart
+22
-22
constants.dart
...on_tests/android_semantics_testing/lib/src/constants.dart
+2
-2
matcher.dart
...tion_tests/android_semantics_testing/lib/src/matcher.dart
+46
-40
controls_page.dart
...ndroid_semantics_testing/lib/src/tests/controls_page.dart
+5
-5
headings_page.dart
...ndroid_semantics_testing/lib/src/tests/headings_page.dart
+1
-1
popup_page.dart
...s/android_semantics_testing/lib/src/tests/popup_page.dart
+3
-3
text_field_page.dart
...roid_semantics_testing/lib/src/tests/text_field_page.dart
+1
-1
pubspec.yaml
dev/integration_tests/android_semantics_testing/pubspec.yaml
+1
-1
main_test.dart
...ests/android_semantics_testing/test_driver/main_test.dart
+4
-3
No files found.
dev/integration_tests/android_semantics_testing/lib/main.dart
View file @
1002a768
...
...
@@ -23,18 +23,18 @@ void main() {
const
MethodChannel
kSemanticsChannel
=
MethodChannel
(
'semantics'
);
Future
<
String
>
dataHandler
(
String
message
)
async
{
if
(
message
.
contains
(
'getSemanticsNode'
))
{
Future
<
String
>
dataHandler
(
String
?
message
)
async
{
if
(
message
!=
null
&&
message
.
contains
(
'getSemanticsNode'
))
{
final
Completer
<
String
>
completer
=
Completer
<
String
>();
final
int
id
=
int
.
tryParse
(
message
.
split
(
'#'
)[
1
])
??
0
;
Future
<
void
>
completeSemantics
([
Object
_
])
async
{
Future
<
void
>
completeSemantics
([
Object
?
_
])
async
{
final
dynamic
result
=
await
kSemanticsChannel
.
invokeMethod
<
dynamic
>(
'getSemanticsNode'
,
<
String
,
dynamic
>{
'id'
:
id
,
});
completer
.
complete
(
json
.
encode
(
result
));
}
if
(
SchedulerBinding
.
instance
.
hasScheduledFrame
)
SchedulerBinding
.
instance
.
addPostFrameCallback
(
completeSemantics
);
if
(
SchedulerBinding
.
instance
!
.
hasScheduledFrame
)
SchedulerBinding
.
instance
!
.
addPostFrameCallback
(
completeSemantics
);
else
completeSemantics
();
return
completer
.
future
;
...
...
@@ -50,7 +50,7 @@ Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
};
class
TestApp
extends
StatelessWidget
{
const
TestApp
({
Key
key
})
:
super
(
key:
key
);
const
TestApp
({
Key
?
key
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
...
...
dev/integration_tests/android_semantics_testing/lib/src/common.dart
View file @
1002a768
...
...
@@ -53,19 +53,19 @@ class AndroidSemanticsNode {
/// ]
/// }
factory
AndroidSemanticsNode
.
deserialize
(
String
value
)
{
return
AndroidSemanticsNode
.
_
(
json
.
decode
(
value
)
as
Map
<
String
,
Object
>);
return
AndroidSemanticsNode
.
_
(
json
.
decode
(
value
)
as
Map
<
String
,
Object
?
>);
}
final
Map
<
String
,
Object
>
_values
;
final
Map
<
String
,
Object
?
>
_values
;
final
List
<
AndroidSemanticsNode
>
_children
=
<
AndroidSemanticsNode
>[];
Map
<
String
,
Object
>
get
_flags
=>
_values
[
'flags'
]
as
Map
<
String
,
Object
>;
Map
<
String
,
Object
?>
get
_flags
=>
_values
[
'flags'
]!
as
Map
<
String
,
Object
?
>;
/// The text value of the semantics node.
///
/// This is produced by combining the value, label, and hint fields from
/// the Flutter [SemanticsNode].
String
get
text
=>
_values
[
'text'
]
as
String
;
String
get
text
=>
_values
[
'text'
]
!
as
String
;
/// The contentDescription of the semantics node.
///
...
...
@@ -75,7 +75,7 @@ class AndroidSemanticsNode {
///
/// This is produced by combining the value, label, and hint fields from
/// the Flutter [SemanticsNode].
String
get
contentDescription
=>
_values
[
'contentDescription'
]
as
String
;
String
get
contentDescription
=>
_values
[
'contentDescription'
]
!
as
String
;
/// The className of the semantics node.
///
...
...
@@ -84,10 +84,10 @@ class AndroidSemanticsNode {
///
/// If a more specific value isn't provided, it defaults to
/// "android.view.View".
String
get
className
=>
_values
[
'className'
]
as
String
;
String
get
className
=>
_values
[
'className'
]
!
as
String
;
/// The identifier for this semantics node.
int
get
id
=>
_values
[
'id'
]
as
int
;
int
get
id
=>
_values
[
'id'
]
!
as
int
;
/// The children of this semantics node.
List
<
AndroidSemanticsNode
>
get
children
=>
_children
;
...
...
@@ -95,50 +95,50 @@ class AndroidSemanticsNode {
/// Whether the node is currently in a checked state.
///
/// Equivalent to [SemanticsFlag.isChecked].
bool
get
isChecked
=>
_flags
[
'isChecked'
]
as
bool
;
bool
get
isChecked
=>
_flags
[
'isChecked'
]
!
as
bool
;
/// Whether the node can be in a checked state.
///
/// Equivalent to [SemanticsFlag.hasCheckedState]
bool
get
isCheckable
=>
_flags
[
'isCheckable'
]
as
bool
;
bool
get
isCheckable
=>
_flags
[
'isCheckable'
]
!
as
bool
;
/// Whether the node is editable.
///
/// This is usually only applied to text fields, which map
/// to "android.widget.EditText".
bool
get
isEditable
=>
_flags
[
'isEditable'
]
as
bool
;
bool
get
isEditable
=>
_flags
[
'isEditable'
]
!
as
bool
;
/// Whether the node is enabled.
bool
get
isEnabled
=>
_flags
[
'isEnabled'
]
as
bool
;
bool
get
isEnabled
=>
_flags
[
'isEnabled'
]
!
as
bool
;
/// Whether the node is focusable.
bool
get
isFocusable
=>
_flags
[
'isFocusable'
]
as
bool
;
bool
get
isFocusable
=>
_flags
[
'isFocusable'
]
!
as
bool
;
/// Whether the node is focused.
bool
get
isFocused
=>
_flags
[
'isFocused'
]
as
bool
;
bool
get
isFocused
=>
_flags
[
'isFocused'
]
!
as
bool
;
/// Whether the node is considered a heading.
bool
get
isHeading
=>
_flags
[
'isHeading'
]
as
bool
;
bool
get
isHeading
=>
_flags
[
'isHeading'
]
!
as
bool
;
/// Whether the node represents a password field.
///
/// Equivalent to [SemanticsFlag.isObscured].
bool
get
isPassword
=>
_flags
[
'isPassword'
]
as
bool
;
bool
get
isPassword
=>
_flags
[
'isPassword'
]
!
as
bool
;
/// Whether the node is long clickable.
///
/// Equivalent to having [SemanticsAction.longPress].
bool
get
isLongClickable
=>
_flags
[
'isLongClickable'
]
as
bool
;
bool
get
isLongClickable
=>
_flags
[
'isLongClickable'
]
!
as
bool
;
/// Gets a [Rect] which defines the position and size of the semantics node.
Rect
getRect
()
{
final
Map
<
String
,
Object
>
rawRect
=
_values
[
'rect'
]
as
Map
<
String
,
Object
>;
final
Map
<
String
,
Object
?>
rawRect
=
_values
[
'rect'
]!
as
Map
<
String
,
Object
?
>;
final
Map
<
String
,
int
>
rect
=
rawRect
.
cast
<
String
,
int
>();
return
Rect
.
fromLTRB
(
rect
[
'left'
].
toDouble
(),
rect
[
'top'
].
toDouble
(),
rect
[
'right'
].
toDouble
(),
rect
[
'bottom'
].
toDouble
(),
rect
[
'left'
]
!
.
toDouble
(),
rect
[
'top'
]
!
.
toDouble
(),
rect
[
'right'
]
!
.
toDouble
(),
rect
[
'bottom'
]
!
.
toDouble
(),
);
}
...
...
@@ -150,7 +150,7 @@ class AndroidSemanticsNode {
/// Gets a list of [AndroidSemanticsActions] which are defined for the node.
List
<
AndroidSemanticsAction
>
getActions
()
=>
<
AndroidSemanticsAction
>[
for
(
final
int
id
in
(
_values
[
'actions'
]
as
List
<
dynamic
>).
cast
<
int
>())
AndroidSemanticsAction
.
deserialize
(
id
)
,
for
(
final
int
id
in
(
_values
[
'actions'
]
!
as
List
<
dynamic
>).
cast
<
int
>())
AndroidSemanticsAction
.
deserialize
(
id
)!
,
];
@override
...
...
dev/integration_tests/android_semantics_testing/lib/src/constants.dart
View file @
1002a768
...
...
@@ -168,7 +168,7 @@ class AndroidSemanticsAction {
case
_kSetText:
return
'AndroidSemanticsAction.setText'
;
default
:
return
null
;
return
'INVALID'
;
}
}
...
...
@@ -210,7 +210,7 @@ class AndroidSemanticsAction {
/// Creates a new [AndroidSemanticsAction] from an integer `value`.
///
/// Returns `null` if the id is not a known Android accessibility action.
static
AndroidSemanticsAction
deserialize
(
int
value
)
{
static
AndroidSemanticsAction
?
deserialize
(
int
value
)
{
return
_kActionById
[
value
];
}
}
dev/integration_tests/android_semantics_testing/lib/src/matcher.dart
View file @
1002a768
...
...
@@ -18,23 +18,23 @@ import 'constants.dart';
/// the Android accessibility bridge, and not the semantics object created by
/// the Flutter framework.
Matcher
hasAndroidSemantics
(
{
String
text
,
String
contentDescription
,
String
className
,
int
id
,
Rect
rect
,
Size
size
,
List
<
AndroidSemanticsAction
>
actions
,
List
<
AndroidSemanticsNode
>
children
,
bool
isChecked
,
bool
isCheckable
,
bool
isEditable
,
bool
isEnabled
,
bool
isFocusable
,
bool
isFocused
,
bool
isHeading
,
bool
isPassword
,
bool
isLongClickable
,
String
?
text
,
String
?
contentDescription
,
String
?
className
,
int
?
id
,
Rect
?
rect
,
Size
?
size
,
List
<
AndroidSemanticsAction
>
?
actions
,
List
<
AndroidSemanticsNode
>
?
children
,
bool
?
isChecked
,
bool
?
isCheckable
,
bool
?
isEditable
,
bool
?
isEnabled
,
bool
?
isFocusable
,
bool
?
isFocused
,
bool
?
isHeading
,
bool
?
isPassword
,
bool
?
isLongClickable
,
})
{
return
_AndroidSemanticsMatcher
(
text:
text
,
...
...
@@ -76,22 +76,22 @@ class _AndroidSemanticsMatcher extends Matcher {
this
.
isLongClickable
,
});
final
String
text
;
final
String
className
;
final
String
contentDescription
;
final
int
id
;
final
List
<
AndroidSemanticsAction
>
actions
;
final
Rect
rect
;
final
Size
size
;
final
bool
isChecked
;
final
bool
isCheckable
;
final
bool
isEditable
;
final
bool
isEnabled
;
final
bool
isFocusable
;
final
bool
isFocused
;
final
bool
isHeading
;
final
bool
isPassword
;
final
bool
isLongClickable
;
final
String
?
text
;
final
String
?
className
;
final
String
?
contentDescription
;
final
int
?
id
;
final
List
<
AndroidSemanticsAction
>
?
actions
;
final
Rect
?
rect
;
final
Size
?
size
;
final
bool
?
isChecked
;
final
bool
?
isCheckable
;
final
bool
?
isEditable
;
final
bool
?
isEnabled
;
final
bool
?
isFocusable
;
final
bool
?
isFocused
;
final
bool
?
isHeading
;
final
bool
?
isPassword
;
final
bool
?
isLongClickable
;
@override
Description
describe
(
Description
description
)
{
...
...
@@ -130,7 +130,9 @@ class _AndroidSemanticsMatcher extends Matcher {
}
@override
bool
matches
(
covariant
AndroidSemanticsNode
item
,
Map
<
Object
,
Object
>
matchState
)
{
bool
matches
(
covariant
AndroidSemanticsNode
?
item
,
Map
<
Object
?,
Object
?>
matchState
)
{
if
(
item
is
!
AndroidSemanticsNode
)
return
_failWithMessage
(
'Expected an AndroidSemanticsNode, but got:
$item
'
,
matchState
);
if
(
text
!=
null
&&
text
!=
item
.
text
)
return
_failWithMessage
(
'Expected text:
$text
'
,
matchState
);
if
(
contentDescription
!=
null
&&
contentDescription
!=
item
.
contentDescription
)
...
...
@@ -145,8 +147,8 @@ class _AndroidSemanticsMatcher extends Matcher {
return
_failWithMessage
(
'Expected size:
$size
'
,
matchState
);
if
(
actions
!=
null
)
{
final
List
<
AndroidSemanticsAction
>
itemActions
=
item
.
getActions
();
if
(!
unorderedEquals
(
actions
).
matches
(
itemActions
,
matchState
))
{
final
List
<
String
>
actionsString
=
actions
.
map
<
String
>((
AndroidSemanticsAction
action
)
=>
action
.
toString
()).
toList
()..
sort
();
if
(!
unorderedEquals
(
actions
!
).
matches
(
itemActions
,
matchState
))
{
final
List
<
String
>
actionsString
=
actions
!
.
map
<
String
>((
AndroidSemanticsAction
action
)
=>
action
.
toString
()).
toList
()..
sort
();
final
List
<
String
>
itemActionsString
=
itemActions
.
map
<
String
>((
AndroidSemanticsAction
action
)
=>
action
.
toString
()).
toList
()..
sort
();
final
Set
<
String
>
unexpected
=
itemActionsString
.
toSet
().
difference
(
actionsString
.
toSet
());
final
Set
<
String
>
missing
=
actionsString
.
toSet
().
difference
(
itemActionsString
.
toSet
());
...
...
@@ -176,12 +178,16 @@ class _AndroidSemanticsMatcher extends Matcher {
}
@override
Description
describeMismatch
(
Object
item
,
Description
mismatchDescription
,
Map
<
Object
,
Object
>
matchState
,
bool
verbose
)
{
return
mismatchDescription
.
add
(
matchState
[
'failure'
]
as
String
);
Description
describeMismatch
(
Object
?
item
,
Description
mismatchDescription
,
Map
<
Object
?,
Object
?>
matchState
,
bool
verbose
,
)
{
return
mismatchDescription
.
add
(
matchState
[
'failure'
]!
as
String
);
}
bool
_failWithMessage
(
String
value
,
Map
<
dynamic
,
dynamic
>
matchState
)
{
bool
_failWithMessage
(
String
value
,
Map
<
Object
?,
Object
?
>
matchState
)
{
matchState
[
'failure'
]
=
value
;
return
false
;
}
...
...
dev/integration_tests/android_semantics_testing/lib/src/tests/controls_page.dart
View file @
1002a768
...
...
@@ -9,7 +9,7 @@ export 'controls_constants.dart';
/// A test page with a checkbox, three radio buttons, and a switch.
class
SelectionControlsPage
extends
StatefulWidget
{
const
SelectionControlsPage
({
Key
key
})
:
super
(
key:
key
);
const
SelectionControlsPage
({
Key
?
key
})
:
super
(
key:
key
);
@override
State
<
StatefulWidget
>
createState
()
=>
_SelectionControlsPageState
();
...
...
@@ -28,15 +28,15 @@ class _SelectionControlsPageState extends State<SelectionControlsPage> {
bool
_isLabeledOn
=
false
;
int
_radio
=
0
;
void
_updateCheckbox
(
bool
newValue
)
{
void
_updateCheckbox
(
bool
?
newValue
)
{
setState
(()
{
_isChecked
=
newValue
;
_isChecked
=
newValue
!
;
});
}
void
_updateRadio
(
int
newValue
)
{
void
_updateRadio
(
int
?
newValue
)
{
setState
(()
{
_radio
=
newValue
;
_radio
=
newValue
!
;
});
}
...
...
dev/integration_tests/android_semantics_testing/lib/src/tests/headings_page.dart
View file @
1002a768
...
...
@@ -9,7 +9,7 @@ export 'headings_constants.dart';
/// A test page with an app bar and some body text for testing heading flags.
class
HeadingsPage
extends
StatelessWidget
{
const
HeadingsPage
({
Key
key
})
:
super
(
key:
key
);
const
HeadingsPage
({
Key
?
key
})
:
super
(
key:
key
);
static
const
ValueKey
<
String
>
_appBarTitleKey
=
ValueKey
<
String
>(
appBarTitleKeyValue
);
static
const
ValueKey
<
String
>
_bodyTextKey
=
ValueKey
<
String
>(
bodyTextKeyValue
);
...
...
dev/integration_tests/android_semantics_testing/lib/src/tests/popup_page.dart
View file @
1002a768
...
...
@@ -10,7 +10,7 @@ export 'popup_constants.dart';
/// A page with a popup menu, a dropdown menu, and a modal alert.
class
PopupControlsPage
extends
StatefulWidget
{
const
PopupControlsPage
({
Key
key
})
:
super
(
key:
key
);
const
PopupControlsPage
({
Key
?
key
})
:
super
(
key:
key
);
@override
State
<
StatefulWidget
>
createState
()
=>
_PopupControlsPageState
();
...
...
@@ -22,7 +22,7 @@ class _PopupControlsPageState extends State<PopupControlsPage> {
final
Key
alertKey
=
const
ValueKey
<
String
>(
alertKeyValue
);
String
popupValue
=
popupItems
.
first
;
String
dropdownValue
=
popupItems
.
first
;
String
?
dropdownValue
=
popupItems
.
first
;
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -60,7 +60,7 @@ class _PopupControlsPageState extends State<PopupControlsPage> {
child:
Text
(
item
),
);
}).
toList
(),
onChanged:
(
String
value
)
{
onChanged:
(
String
?
value
)
{
setState
(()
{
dropdownValue
=
value
;
});
...
...
dev/integration_tests/android_semantics_testing/lib/src/tests/text_field_page.dart
View file @
1002a768
...
...
@@ -10,7 +10,7 @@ export 'text_field_constants.dart';
/// A page with a normal text field and a password field.
class
TextFieldPage
extends
StatefulWidget
{
const
TextFieldPage
({
Key
key
})
:
super
(
key:
key
);
const
TextFieldPage
({
Key
?
key
})
:
super
(
key:
key
);
@override
State
<
StatefulWidget
>
createState
()
=>
_TextFieldPageState
();
...
...
dev/integration_tests/android_semantics_testing/pubspec.yaml
View file @
1002a768
name
:
android_semantics_testing
description
:
Integration testing library for Android semantics
environment
:
sdk
:
'
>=2.
9
.0
<3.0.0'
sdk
:
'
>=2.
12
.0
<3.0.0'
dependencies
:
flutter
:
...
...
dev/integration_tests/android_semantics_testing/test_driver/main_test.dart
View file @
1002a768
...
...
@@ -11,7 +11,7 @@ import 'package:path/path.dart' as path;
import
'package:test/test.dart'
hide
isInstanceOf
;
String
adbPath
(
)
{
final
String
androidHome
=
io
.
Platform
.
environment
[
'ANDROID_HOME'
]
??
io
.
Platform
.
environment
[
'ANDROID_SDK_ROOT'
];
final
String
?
androidHome
=
io
.
Platform
.
environment
[
'ANDROID_HOME'
]
??
io
.
Platform
.
environment
[
'ANDROID_SDK_ROOT'
];
if
(
androidHome
==
null
)
{
return
'adb'
;
}
else
{
...
...
@@ -21,7 +21,7 @@ String adbPath() {
void
main
(
)
{
group
(
'AccessibilityBridge'
,
()
{
FlutterDriver
driver
;
late
FlutterDriver
driver
;
Future
<
AndroidSemanticsNode
>
getSemantics
(
SerializableFinder
finder
)
async
{
final
int
id
=
await
driver
.
getSemanticsId
(
finder
);
final
String
data
=
await
driver
.
requestData
(
'getSemanticsNode#
$id
'
);
...
...
@@ -53,7 +53,7 @@ void main() {
'null'
,
]);
await
run
.
exitCode
;
driver
?
.
close
();
driver
.
close
();
});
group
(
'TextField'
,
()
{
...
...
@@ -658,6 +658,7 @@ void main() {
group
(
'Headings'
,
()
{
setUpAll
(()
async
{
await
driver
.
tap
(
find
.
text
(
headingsRoute
));
await
driver
.
waitFor
(
find
.
byValueKey
(
appBarTitleKeyValue
));
});
test
(
'AppBar title has correct Android heading semantics'
,
()
async
{
...
...
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