Unverified Commit 9aa82946 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Revert "Reland "Migrate android_semantics_testing to null safety" (#90466)" (#90483)

This reverts commit 1002a768.
parent 1002a768
...@@ -23,18 +23,18 @@ void main() { ...@@ -23,18 +23,18 @@ void main() {
const MethodChannel kSemanticsChannel = MethodChannel('semantics'); const MethodChannel kSemanticsChannel = MethodChannel('semantics');
Future<String> dataHandler(String? message) async { Future<String> dataHandler(String message) async {
if (message != null && message.contains('getSemanticsNode')) { if (message.contains('getSemanticsNode')) {
final Completer<String> completer = Completer<String>(); final Completer<String> completer = Completer<String>();
final int id = int.tryParse(message.split('#')[1]) ?? 0; 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>{ final dynamic result = await kSemanticsChannel.invokeMethod<dynamic>('getSemanticsNode', <String, dynamic>{
'id': id, 'id': id,
}); });
completer.complete(json.encode(result)); completer.complete(json.encode(result));
} }
if (SchedulerBinding.instance!.hasScheduledFrame) if (SchedulerBinding.instance.hasScheduledFrame)
SchedulerBinding.instance!.addPostFrameCallback(completeSemantics); SchedulerBinding.instance.addPostFrameCallback(completeSemantics);
else else
completeSemantics(); completeSemantics();
return completer.future; return completer.future;
...@@ -50,7 +50,7 @@ Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ ...@@ -50,7 +50,7 @@ Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
}; };
class TestApp extends StatelessWidget { class TestApp extends StatelessWidget {
const TestApp({Key? key}) : super(key: key); const TestApp({Key key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
......
...@@ -53,19 +53,19 @@ class AndroidSemanticsNode { ...@@ -53,19 +53,19 @@ class AndroidSemanticsNode {
/// ] /// ]
/// } /// }
factory AndroidSemanticsNode.deserialize(String value) { 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>[]; 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. /// The text value of the semantics node.
/// ///
/// This is produced by combining the value, label, and hint fields from /// This is produced by combining the value, label, and hint fields from
/// the Flutter [SemanticsNode]. /// the Flutter [SemanticsNode].
String get text => _values['text']! as String; String get text => _values['text'] as String;
/// The contentDescription of the semantics node. /// The contentDescription of the semantics node.
/// ///
...@@ -75,7 +75,7 @@ class AndroidSemanticsNode { ...@@ -75,7 +75,7 @@ class AndroidSemanticsNode {
/// ///
/// This is produced by combining the value, label, and hint fields from /// This is produced by combining the value, label, and hint fields from
/// the Flutter [SemanticsNode]. /// the Flutter [SemanticsNode].
String get contentDescription => _values['contentDescription']! as String; String get contentDescription => _values['contentDescription'] as String;
/// The className of the semantics node. /// The className of the semantics node.
/// ///
...@@ -84,10 +84,10 @@ class AndroidSemanticsNode { ...@@ -84,10 +84,10 @@ class AndroidSemanticsNode {
/// ///
/// If a more specific value isn't provided, it defaults to /// If a more specific value isn't provided, it defaults to
/// "android.view.View". /// "android.view.View".
String get className => _values['className']! as String; String get className => _values['className'] as String;
/// The identifier for this semantics node. /// 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. /// The children of this semantics node.
List<AndroidSemanticsNode> get children => _children; List<AndroidSemanticsNode> get children => _children;
...@@ -95,50 +95,50 @@ class AndroidSemanticsNode { ...@@ -95,50 +95,50 @@ class AndroidSemanticsNode {
/// Whether the node is currently in a checked state. /// Whether the node is currently in a checked state.
/// ///
/// Equivalent to [SemanticsFlag.isChecked]. /// 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. /// Whether the node can be in a checked state.
/// ///
/// Equivalent to [SemanticsFlag.hasCheckedState] /// Equivalent to [SemanticsFlag.hasCheckedState]
bool get isCheckable => _flags['isCheckable']! as bool; bool get isCheckable => _flags['isCheckable'] as bool;
/// Whether the node is editable. /// Whether the node is editable.
/// ///
/// This is usually only applied to text fields, which map /// This is usually only applied to text fields, which map
/// to "android.widget.EditText". /// to "android.widget.EditText".
bool get isEditable => _flags['isEditable']! as bool; bool get isEditable => _flags['isEditable'] as bool;
/// Whether the node is enabled. /// Whether the node is enabled.
bool get isEnabled => _flags['isEnabled']! as bool; bool get isEnabled => _flags['isEnabled'] as bool;
/// Whether the node is focusable. /// Whether the node is focusable.
bool get isFocusable => _flags['isFocusable']! as bool; bool get isFocusable => _flags['isFocusable'] as bool;
/// Whether the node is focused. /// 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. /// 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. /// Whether the node represents a password field.
/// ///
/// Equivalent to [SemanticsFlag.isObscured]. /// Equivalent to [SemanticsFlag.isObscured].
bool get isPassword => _flags['isPassword']! as bool; bool get isPassword => _flags['isPassword'] as bool;
/// Whether the node is long clickable. /// Whether the node is long clickable.
/// ///
/// Equivalent to having [SemanticsAction.longPress]. /// 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. /// Gets a [Rect] which defines the position and size of the semantics node.
Rect getRect() { 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>(); final Map<String, int> rect = rawRect.cast<String, int>();
return Rect.fromLTRB( return Rect.fromLTRB(
rect['left']!.toDouble(), rect['left'].toDouble(),
rect['top']!.toDouble(), rect['top'].toDouble(),
rect['right']!.toDouble(), rect['right'].toDouble(),
rect['bottom']!.toDouble(), rect['bottom'].toDouble(),
); );
} }
...@@ -150,7 +150,7 @@ class AndroidSemanticsNode { ...@@ -150,7 +150,7 @@ class AndroidSemanticsNode {
/// Gets a list of [AndroidSemanticsActions] which are defined for the node. /// Gets a list of [AndroidSemanticsActions] which are defined for the node.
List<AndroidSemanticsAction> getActions() => <AndroidSemanticsAction>[ 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 @override
......
...@@ -168,7 +168,7 @@ class AndroidSemanticsAction { ...@@ -168,7 +168,7 @@ class AndroidSemanticsAction {
case _kSetText: case _kSetText:
return 'AndroidSemanticsAction.setText'; return 'AndroidSemanticsAction.setText';
default: default:
return 'INVALID'; return null;
} }
} }
...@@ -210,7 +210,7 @@ class AndroidSemanticsAction { ...@@ -210,7 +210,7 @@ class AndroidSemanticsAction {
/// Creates a new [AndroidSemanticsAction] from an integer `value`. /// Creates a new [AndroidSemanticsAction] from an integer `value`.
/// ///
/// Returns `null` if the id is not a known Android accessibility action. /// 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]; return _kActionById[value];
} }
} }
...@@ -18,23 +18,23 @@ import 'constants.dart'; ...@@ -18,23 +18,23 @@ import 'constants.dart';
/// the Android accessibility bridge, and not the semantics object created by /// the Android accessibility bridge, and not the semantics object created by
/// the Flutter framework. /// the Flutter framework.
Matcher hasAndroidSemantics({ Matcher hasAndroidSemantics({
String? text, String text,
String? contentDescription, String contentDescription,
String? className, String className,
int? id, int id,
Rect? rect, Rect rect,
Size? size, Size size,
List<AndroidSemanticsAction>? actions, List<AndroidSemanticsAction> actions,
List<AndroidSemanticsNode>? children, List<AndroidSemanticsNode> children,
bool? isChecked, bool isChecked,
bool? isCheckable, bool isCheckable,
bool? isEditable, bool isEditable,
bool? isEnabled, bool isEnabled,
bool? isFocusable, bool isFocusable,
bool? isFocused, bool isFocused,
bool? isHeading, bool isHeading,
bool? isPassword, bool isPassword,
bool? isLongClickable, bool isLongClickable,
}) { }) {
return _AndroidSemanticsMatcher( return _AndroidSemanticsMatcher(
text: text, text: text,
...@@ -76,22 +76,22 @@ class _AndroidSemanticsMatcher extends Matcher { ...@@ -76,22 +76,22 @@ class _AndroidSemanticsMatcher extends Matcher {
this.isLongClickable, this.isLongClickable,
}); });
final String? text; final String text;
final String? className; final String className;
final String? contentDescription; final String contentDescription;
final int? id; final int id;
final List<AndroidSemanticsAction>? actions; final List<AndroidSemanticsAction> actions;
final Rect? rect; final Rect rect;
final Size? size; final Size size;
final bool? isChecked; final bool isChecked;
final bool? isCheckable; final bool isCheckable;
final bool? isEditable; final bool isEditable;
final bool? isEnabled; final bool isEnabled;
final bool? isFocusable; final bool isFocusable;
final bool? isFocused; final bool isFocused;
final bool? isHeading; final bool isHeading;
final bool? isPassword; final bool isPassword;
final bool? isLongClickable; final bool isLongClickable;
@override @override
Description describe(Description description) { Description describe(Description description) {
...@@ -130,9 +130,7 @@ class _AndroidSemanticsMatcher extends Matcher { ...@@ -130,9 +130,7 @@ class _AndroidSemanticsMatcher extends Matcher {
} }
@override @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) if (text != null && text != item.text)
return _failWithMessage('Expected text: $text', matchState); return _failWithMessage('Expected text: $text', matchState);
if (contentDescription != null && contentDescription != item.contentDescription) if (contentDescription != null && contentDescription != item.contentDescription)
...@@ -147,8 +145,8 @@ class _AndroidSemanticsMatcher extends Matcher { ...@@ -147,8 +145,8 @@ class _AndroidSemanticsMatcher extends Matcher {
return _failWithMessage('Expected size: $size', matchState); return _failWithMessage('Expected size: $size', matchState);
if (actions != null) { if (actions != null) {
final List<AndroidSemanticsAction> itemActions = item.getActions(); final List<AndroidSemanticsAction> itemActions = item.getActions();
if (!unorderedEquals(actions!).matches(itemActions, matchState)) { if (!unorderedEquals(actions).matches(itemActions, matchState)) {
final List<String> actionsString = actions!.map<String>((AndroidSemanticsAction action) => action.toString()).toList()..sort(); 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 List<String> itemActionsString = itemActions.map<String>((AndroidSemanticsAction action) => action.toString()).toList()..sort();
final Set<String> unexpected = itemActionsString.toSet().difference(actionsString.toSet()); final Set<String> unexpected = itemActionsString.toSet().difference(actionsString.toSet());
final Set<String> missing = actionsString.toSet().difference(itemActionsString.toSet()); final Set<String> missing = actionsString.toSet().difference(itemActionsString.toSet());
...@@ -178,16 +176,12 @@ class _AndroidSemanticsMatcher extends Matcher { ...@@ -178,16 +176,12 @@ class _AndroidSemanticsMatcher extends Matcher {
} }
@override @override
Description describeMismatch( Description describeMismatch(Object item, Description mismatchDescription,
Object? item, Map<Object, Object> matchState, bool verbose) {
Description mismatchDescription, return mismatchDescription.add(matchState['failure'] as String);
Map<Object?, Object?> matchState,
bool verbose,
) {
return mismatchDescription.add(matchState['failure']! as String);
} }
bool _failWithMessage(String value, Map<Object?, Object?> matchState) { bool _failWithMessage(String value, Map<dynamic, dynamic> matchState) {
matchState['failure'] = value; matchState['failure'] = value;
return false; return false;
} }
......
...@@ -9,7 +9,7 @@ export 'controls_constants.dart'; ...@@ -9,7 +9,7 @@ export 'controls_constants.dart';
/// A test page with a checkbox, three radio buttons, and a switch. /// A test page with a checkbox, three radio buttons, and a switch.
class SelectionControlsPage extends StatefulWidget { class SelectionControlsPage extends StatefulWidget {
const SelectionControlsPage({Key? key}) : super(key: key); const SelectionControlsPage({Key key}) : super(key: key);
@override @override
State<StatefulWidget> createState() => _SelectionControlsPageState(); State<StatefulWidget> createState() => _SelectionControlsPageState();
...@@ -28,15 +28,15 @@ class _SelectionControlsPageState extends State<SelectionControlsPage> { ...@@ -28,15 +28,15 @@ class _SelectionControlsPageState extends State<SelectionControlsPage> {
bool _isLabeledOn = false; bool _isLabeledOn = false;
int _radio = 0; int _radio = 0;
void _updateCheckbox(bool? newValue) { void _updateCheckbox(bool newValue) {
setState(() { setState(() {
_isChecked = newValue!; _isChecked = newValue;
}); });
} }
void _updateRadio(int? newValue) { void _updateRadio(int newValue) {
setState(() { setState(() {
_radio = newValue!; _radio = newValue;
}); });
} }
......
...@@ -9,7 +9,7 @@ export 'headings_constants.dart'; ...@@ -9,7 +9,7 @@ export 'headings_constants.dart';
/// A test page with an app bar and some body text for testing heading flags. /// A test page with an app bar and some body text for testing heading flags.
class HeadingsPage extends StatelessWidget { 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> _appBarTitleKey = ValueKey<String>(appBarTitleKeyValue);
static const ValueKey<String> _bodyTextKey = ValueKey<String>(bodyTextKeyValue); static const ValueKey<String> _bodyTextKey = ValueKey<String>(bodyTextKeyValue);
......
...@@ -10,7 +10,7 @@ export 'popup_constants.dart'; ...@@ -10,7 +10,7 @@ export 'popup_constants.dart';
/// A page with a popup menu, a dropdown menu, and a modal alert. /// A page with a popup menu, a dropdown menu, and a modal alert.
class PopupControlsPage extends StatefulWidget { class PopupControlsPage extends StatefulWidget {
const PopupControlsPage({Key? key}) : super(key: key); const PopupControlsPage({Key key}) : super(key: key);
@override @override
State<StatefulWidget> createState() => _PopupControlsPageState(); State<StatefulWidget> createState() => _PopupControlsPageState();
...@@ -22,7 +22,7 @@ class _PopupControlsPageState extends State<PopupControlsPage> { ...@@ -22,7 +22,7 @@ class _PopupControlsPageState extends State<PopupControlsPage> {
final Key alertKey = const ValueKey<String>(alertKeyValue); final Key alertKey = const ValueKey<String>(alertKeyValue);
String popupValue = popupItems.first; String popupValue = popupItems.first;
String? dropdownValue = popupItems.first; String dropdownValue = popupItems.first;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -60,7 +60,7 @@ class _PopupControlsPageState extends State<PopupControlsPage> { ...@@ -60,7 +60,7 @@ class _PopupControlsPageState extends State<PopupControlsPage> {
child: Text(item), child: Text(item),
); );
}).toList(), }).toList(),
onChanged: (String? value) { onChanged: (String value) {
setState(() { setState(() {
dropdownValue = value; dropdownValue = value;
}); });
......
...@@ -10,7 +10,7 @@ export 'text_field_constants.dart'; ...@@ -10,7 +10,7 @@ export 'text_field_constants.dart';
/// A page with a normal text field and a password field. /// A page with a normal text field and a password field.
class TextFieldPage extends StatefulWidget { class TextFieldPage extends StatefulWidget {
const TextFieldPage({Key? key}) : super(key: key); const TextFieldPage({Key key}) : super(key: key);
@override @override
State<StatefulWidget> createState() => _TextFieldPageState(); State<StatefulWidget> createState() => _TextFieldPageState();
......
name: android_semantics_testing name: android_semantics_testing
description: Integration testing library for Android semantics description: Integration testing library for Android semantics
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: '>=2.9.0 <3.0.0'
dependencies: dependencies:
flutter: flutter:
......
...@@ -11,7 +11,7 @@ import 'package:path/path.dart' as path; ...@@ -11,7 +11,7 @@ import 'package:path/path.dart' as path;
import 'package:test/test.dart' hide isInstanceOf; import 'package:test/test.dart' hide isInstanceOf;
String adbPath() { 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) { if (androidHome == null) {
return 'adb'; return 'adb';
} else { } else {
...@@ -21,7 +21,7 @@ String adbPath() { ...@@ -21,7 +21,7 @@ String adbPath() {
void main() { void main() {
group('AccessibilityBridge', () { group('AccessibilityBridge', () {
late FlutterDriver driver; FlutterDriver driver;
Future<AndroidSemanticsNode> getSemantics(SerializableFinder finder) async { Future<AndroidSemanticsNode> getSemantics(SerializableFinder finder) async {
final int id = await driver.getSemanticsId(finder); final int id = await driver.getSemanticsId(finder);
final String data = await driver.requestData('getSemanticsNode#$id'); final String data = await driver.requestData('getSemanticsNode#$id');
...@@ -53,7 +53,7 @@ void main() { ...@@ -53,7 +53,7 @@ void main() {
'null', 'null',
]); ]);
await run.exitCode; await run.exitCode;
driver.close(); driver?.close();
}); });
group('TextField', () { group('TextField', () {
...@@ -658,7 +658,6 @@ void main() { ...@@ -658,7 +658,6 @@ void main() {
group('Headings', () { group('Headings', () {
setUpAll(() async { setUpAll(() async {
await driver.tap(find.text(headingsRoute)); await driver.tap(find.text(headingsRoute));
await driver.waitFor(find.byValueKey(appBarTitleKeyValue));
}); });
test('AppBar title has correct Android heading semantics', () async { test('AppBar title has correct Android heading semantics', () async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment