Unverified Commit 70f21de9 authored by chunhtai's avatar chunhtai Committed by GitHub

reland always adds alert label for alert dialog in Android (#66057)

parent 0cf1b407
......@@ -613,8 +613,8 @@ void main() {
isEnabled: true,
isFocusable: true,
actions: <AndroidSemanticsAction>[
if (item == 'Body1') AndroidSemanticsAction.clearAccessibilityFocus,
if (item != 'Body1') AndroidSemanticsAction.accessibilityFocus,
if (item == 'Title') AndroidSemanticsAction.clearAccessibilityFocus,
if (item != 'Title') AndroidSemanticsAction.accessibilityFocus,
],
),
reason: "Alert $item button doesn't have the right semantics");
......
......@@ -413,9 +413,11 @@ class AlertDialog extends StatelessWidget {
/// The semantic label of the dialog used by accessibility frameworks to
/// announce screen transitions when the dialog is opened and closed.
///
/// If this label is not provided, a semantic label will be inferred from the
/// [title] if it is not null. If there is no title, the label will be taken
/// from [MaterialLocalizations.alertDialogLabel].
/// In iOS, if this label is not provided, a semantic label will be inferred
/// from the [title] if it is not null.
///
/// In Android, if this label is not provided, the dialog will use the
/// [MaterialLocalizations.alertDialogLabel] as its label.
///
/// See also:
///
......@@ -455,18 +457,15 @@ class AlertDialog extends StatelessWidget {
final DialogTheme dialogTheme = DialogTheme.of(context);
String label = semanticLabel;
if (title == null) {
switch (theme.platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
label = semanticLabel;
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
label = semanticLabel ?? MaterialLocalizations.of(context)?.alertDialogLabel;
}
switch (theme.platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
label ??= MaterialLocalizations.of(context)?.alertDialogLabel;
}
// The paddingScaleFactor is used to adjust the padding of Dialog's
......@@ -491,7 +490,7 @@ class AlertDialog extends StatelessWidget {
style: titleTextStyle ?? dialogTheme.titleTextStyle ?? theme.textTheme.headline6,
child: Semantics(
child: title,
namesRoute: true,
namesRoute: label == null,
container: true,
),
),
......@@ -569,6 +568,8 @@ class AlertDialog extends StatelessWidget {
if (label != null)
dialogChild = Semantics(
scopesRoute: true,
explicitChildNodes: true,
namesRoute: true,
label: label,
child: dialogChild,
......
......@@ -1275,10 +1275,12 @@ void main() {
));
});
testWidgets('Dialog widget contains route semantics from title', (WidgetTester tester) async {
testWidgets('AlertDialog widget contains route semantics from title for iOS', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Builder(
builder: (BuildContext context) {
......@@ -1321,6 +1323,62 @@ void main() {
semantics.dispose();
});
testWidgets('AlertDialog widget always contains alert route semantics for android', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
home: Material(
child: Builder(
builder: (BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('X'),
onPressed: () {
showDialog<void>(
context: context,
builder: (BuildContext context) {
return const AlertDialog(
title: Text('Title'),
content: Text('Y'),
actions: <Widget>[],
);
},
);
},
),
);
},
),
),
),
);
expect(semantics, isNot(includesNodeWith(
label: 'Title',
flags: <SemanticsFlag>[SemanticsFlag.namesRoute],
)));
expect(semantics, isNot(includesNodeWith(
label: 'Alert',
flags: <SemanticsFlag>[SemanticsFlag.namesRoute, SemanticsFlag.scopesRoute],
)));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
// It does not use 'Title' as route semantics
expect(semantics, isNot(includesNodeWith(
label: 'Title',
flags: <SemanticsFlag>[SemanticsFlag.namesRoute],
)));
expect(semantics, includesNodeWith(
label: 'Alert',
flags: <SemanticsFlag>[SemanticsFlag.namesRoute, SemanticsFlag.scopesRoute],
));
semantics.dispose();
});
testWidgets('Dismissible.confirmDismiss defers to an AlertDialog', (WidgetTester tester) async {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final List<int> dismissedItems = <int>[];
......
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