diff --git a/engine/src/flutter/lib/ui/window.dart b/engine/src/flutter/lib/ui/window.dart index a49364c5937..48a18692cf8 100644 --- a/engine/src/flutter/lib/ui/window.dart +++ b/engine/src/flutter/lib/ui/window.dart @@ -931,7 +931,6 @@ class AccessibilityFeatures { static const int _kReduceMotionIndex = 1 << 4; static const int _kHighContrastIndex = 1 << 5; static const int _kOnOffSwitchLabelsIndex = 1 << 6; - static const int _kNoAnnounceIndex = 1 << 7; // A bitfield which represents each enabled feature. final int _index; @@ -969,20 +968,6 @@ class AccessibilityFeatures { /// Only supported on iOS. bool get onOffSwitchLabels => _kOnOffSwitchLabelsIndex & _index != 0; - /// Whether accessibility announcements (like [SemanticsService.announce]) - /// are allowed on the current platform. - /// - /// Returns `false` on Android, where platform announcements are deprecated - /// by the underlying platform. - /// - /// Returns `true` on all other platforms (iOS, web, desktop) where such - /// announcements are generally supported without discouragement. - /// - /// Use this flag to conditionally avoid making announcements on Android. - // This is an inverted check on _index since there are many more platforms - // that support announce whereas don't. - bool get announce => _kNoAnnounceIndex & _index == 0; - @override String toString() { final List features = []; @@ -1007,9 +992,6 @@ class AccessibilityFeatures { if (onOffSwitchLabels) { features.add('onOffSwitchLabels'); } - if (announce) { - features.add('announce'); - } return 'AccessibilityFeatures$features'; } diff --git a/engine/src/flutter/lib/ui/window/platform_configuration.h b/engine/src/flutter/lib/ui/window/platform_configuration.h index 36e5ddac1ff..29ee8ca4fff 100644 --- a/engine/src/flutter/lib/ui/window/platform_configuration.h +++ b/engine/src/flutter/lib/ui/window/platform_configuration.h @@ -48,7 +48,6 @@ enum class AccessibilityFeatureFlag : int32_t { kReduceMotion = 1 << 4, kHighContrast = 1 << 5, kOnOffSwitchLabels = 1 << 6, - kNoAnnounce = 1 << 7, }; //-------------------------------------------------------------------------- diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart index 21bf446e1c7..825c96f8aa9 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -54,7 +54,6 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { static const int _kReduceMotionIndex = 1 << 4; static const int _kHighContrastIndex = 1 << 5; static const int _kOnOffSwitchLabelsIndex = 1 << 6; - static const int _kNoAnnounceIndex = 1 << 7; // A bitfield which represents each enabled feature. final int _index; @@ -73,10 +72,6 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { bool get highContrast => _kHighContrastIndex & _index != 0; @override bool get onOffSwitchLabels => _kOnOffSwitchLabelsIndex & _index != 0; - // This is an inverted check on _index since there are many more platforms - // that support announce whereas don't. - @override - bool get announce => _kNoAnnounceIndex & _index == 0; @override String toString() { @@ -102,9 +97,6 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { if (onOffSwitchLabels) { features.add('onOffSwitchLabels'); } - if (announce) { - features.add('announce'); - } return 'AccessibilityFeatures$features'; } @@ -127,7 +119,6 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { bool? reduceMotion, bool? highContrast, bool? onOffSwitchLabels, - bool? announce, }) { final EngineAccessibilityFeaturesBuilder builder = EngineAccessibilityFeaturesBuilder(0); @@ -138,7 +129,6 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { builder.reduceMotion = reduceMotion ?? this.reduceMotion; builder.highContrast = highContrast ?? this.highContrast; builder.onOffSwitchLabels = onOffSwitchLabels ?? this.onOffSwitchLabels; - builder.announce = announce ?? this.announce; return builder.build(); } @@ -156,9 +146,6 @@ class EngineAccessibilityFeaturesBuilder { bool get reduceMotion => EngineAccessibilityFeatures._kReduceMotionIndex & _index != 0; bool get highContrast => EngineAccessibilityFeatures._kHighContrastIndex & _index != 0; bool get onOffSwitchLabels => EngineAccessibilityFeatures._kOnOffSwitchLabelsIndex & _index != 0; - // This is an inverted check on _index since there are many more platforms - // that support announce whereas don't. - bool get announce => EngineAccessibilityFeatures._kNoAnnounceIndex & _index == 0; set accessibleNavigation(bool value) { const int accessibleNavigation = EngineAccessibilityFeatures._kAccessibleNavigation; @@ -195,12 +182,6 @@ class EngineAccessibilityFeaturesBuilder { _index = value ? _index | onOffSwitchLabels : _index & ~onOffSwitchLabels; } - set announce(bool value) { - const int noAnnounce = EngineAccessibilityFeatures._kNoAnnounceIndex; - // Since we are using noAnnounce for the embedder, we need to flip the value. - _index = !value ? _index | noAnnounce : _index & ~noAnnounce; - } - /// Creates and returns an instance of EngineAccessibilityFeatures based on the value of _index EngineAccessibilityFeatures build() { return EngineAccessibilityFeatures(_index); diff --git a/engine/src/flutter/lib/web_ui/lib/window.dart b/engine/src/flutter/lib/web_ui/lib/window.dart index 251b719678e..6abd944be64 100644 --- a/engine/src/flutter/lib/web_ui/lib/window.dart +++ b/engine/src/flutter/lib/web_ui/lib/window.dart @@ -115,7 +115,6 @@ abstract class AccessibilityFeatures { bool get reduceMotion; bool get highContrast; bool get onOffSwitchLabels; - bool get announce; } enum Brightness { dark, light } diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart index c5877ef8714..7d1c646624a 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -299,14 +299,6 @@ void _testEngineAccessibilityBuilder() { expect(features.onOffSwitchLabels, isTrue); }); - test('announce', () { - // By default this starts off true, see EngineAccessibilityFeatures.announce - expect(features.announce, isTrue); - builder.announce = false; - features = builder.build(); - expect(features.announce, isFalse); - }); - test('reduce motion', () { expect(features.reduceMotion, isFalse); builder.reduceMotion = true; @@ -399,10 +391,7 @@ void _testEngineSemanticsOwner() { }); test('accessibilityFeatures copyWith function works', () { - // Announce is an inverted check, see EngineAccessibilityFeatures.announce. - // Therefore, we need to ensure that the original copy starts with false (1 << 7). - const EngineAccessibilityFeatures original = EngineAccessibilityFeatures(0 | 1 << 7); - + const EngineAccessibilityFeatures original = EngineAccessibilityFeatures(0); EngineAccessibilityFeatures copy = original.copyWith(accessibleNavigation: true); expect(copy.accessibleNavigation, true); expect(copy.boldText, false); @@ -410,7 +399,6 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); - expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(boldText: true); @@ -429,7 +417,6 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); - expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(highContrast: true); @@ -439,7 +426,6 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, true); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); - expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(invertColors: true); @@ -449,7 +435,6 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, true); expect(copy.onOffSwitchLabels, false); - expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(onOffSwitchLabels: true); @@ -461,16 +446,6 @@ void _testEngineSemanticsOwner() { expect(copy.onOffSwitchLabels, true); expect(copy.reduceMotion, false); - copy = original.copyWith(announce: true); - expect(copy.accessibleNavigation, false); - expect(copy.boldText, false); - expect(copy.disableAnimations, false); - expect(copy.highContrast, false); - expect(copy.invertColors, false); - expect(copy.onOffSwitchLabels, false); - expect(copy.announce, true); - expect(copy.reduceMotion, false); - copy = original.copyWith(reduceMotion: true); expect(copy.accessibleNavigation, false); expect(copy.boldText, false); @@ -478,7 +453,6 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); - expect(copy.announce, false); expect(copy.reduceMotion, true); }); diff --git a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java index fa7f7fdc792..914c6e2a9ba 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -490,7 +490,6 @@ public class AccessibilityBridge extends AccessibilityNodeProvider { this.accessibilityManager.addTouchExplorationStateChangeListener( touchExplorationStateChangeListener); - accessibilityFeatureFlags |= AccessibilityFeature.NO_ANNOUNCE.value; // Tell Flutter whether animations should initially be enabled or disabled. Then register a // listener to be notified of changes in the future. animationScaleObserver.onChange(false); @@ -2171,8 +2170,7 @@ public class AccessibilityBridge extends AccessibilityNodeProvider { BOLD_TEXT(1 << 3), // NOT SUPPORTED REDUCE_MOTION(1 << 4), // NOT SUPPORTED HIGH_CONTRAST(1 << 5), // NOT SUPPORTED - ON_OFF_SWITCH_LABELS(1 << 6), // NOT SUPPORTED - NO_ANNOUNCE(1 << 7); + ON_OFF_SWITCH_LABELS(1 << 6); // NOT SUPPORTED final int value; diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index 2823c0e454d..c2cf6e624dd 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -66,11 +66,6 @@ import org.robolectric.annotation.Config; @RunWith(AndroidJUnit4.class) public class AccessibilityBridgeTest { - private static final int ACCESSIBILITY_FEATURE_NAVIGATION = 1 << 0; - private static final int ACCESSIBILITY_FEATURE_DISABLE_ANIMATIONS = 1 << 2; - private static final int ACCESSIBILITY_FEATURE_BOLD_TEXT = 1 << 3; - private static final int ACCESSIBILITY_FEATURE_NO_ANNOUNCE = 1 << 7; - @Test public void itDescribesNonTextFieldsWithAContentDescription() { AccessibilityBridge accessibilityBridge = setUpBridge(); @@ -140,26 +135,6 @@ public class AccessibilityBridgeTest { assertEquals(position, outBoundsInScreen.top); } - @Test - public void itSetsNoAnnounceAccessibleFlagByDefault() { - AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); - AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); - AccessibilityManager mockManager = mock(AccessibilityManager.class); - View mockRootView = mock(View.class); - Context context = mock(Context.class); - when(mockRootView.getContext()).thenReturn(context); - when(context.getPackageName()).thenReturn("test"); - when(mockManager.isTouchExplorationEnabled()).thenReturn(false); - setUpBridge( - /*rootAccessibilityView=*/ mockRootView, - /*accessibilityChannel=*/ mockChannel, - /*accessibilityManager=*/ mockManager, - /*contentResolver=*/ null, - /*accessibilityViewEmbedder=*/ mockViewEmbedder, - /*platformViewsAccessibilityDelegate=*/ null); - verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); - } - @Test public void itSetsAccessibleNavigation() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); @@ -183,20 +158,18 @@ public class AccessibilityBridgeTest { verify(mockManager).addTouchExplorationStateChangeListener(listenerCaptor.capture()); assertEquals(accessibilityBridge.getAccessibleNavigation(), false); - verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + verify(mockChannel).setAccessibilityFeatures(0); reset(mockChannel); // Simulate assistive technology accessing accessibility tree. accessibilityBridge.createAccessibilityNodeInfo(0); - verify(mockChannel) - .setAccessibilityFeatures( - ACCESSIBILITY_FEATURE_NAVIGATION | ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + verify(mockChannel).setAccessibilityFeatures(1); assertEquals(accessibilityBridge.getAccessibleNavigation(), true); // Simulate turning off TalkBack. reset(mockChannel); listenerCaptor.getValue().onTouchExplorationStateChanged(false); - verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + verify(mockChannel).setAccessibilityFeatures(0); assertEquals(accessibilityBridge.getAccessibleNavigation(), false); } @@ -1184,9 +1157,7 @@ public class AccessibilityBridgeTest { /*accessibilityViewEmbedder=*/ mockViewEmbedder, /*platformViewsAccessibilityDelegate=*/ null); - verify(mockChannel) - .setAccessibilityFeatures( - ACCESSIBILITY_FEATURE_BOLD_TEXT | ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + verify(mockChannel).setAccessibilityFeatures(1 << 3); reset(mockChannel); // Now verify that clearing the BOLD_TEXT flag doesn't touch any of the other flags. @@ -1208,9 +1179,7 @@ public class AccessibilityBridgeTest { // constructor, verify that the latest argument is correct ArgumentCaptor captor = ArgumentCaptor.forClass(Integer.class); verify(mockChannel, atLeastOnce()).setAccessibilityFeatures(captor.capture()); - assertEquals( - ACCESSIBILITY_FEATURE_DISABLE_ANIMATIONS | ACCESSIBILITY_FEATURE_NO_ANNOUNCE, - captor.getValue().intValue()); + assertEquals(1 << 2 /* DISABLE_ANIMATION */, captor.getValue().intValue()); // Set back to default Settings.Global.putFloat(null, "transition_animation_scale", 1.0f); @@ -1904,21 +1873,19 @@ public class AccessibilityBridgeTest { ContentObserver observer = observerCaptor.getValue(); // Initial state - verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + verify(mockChannel).setAccessibilityFeatures(0); reset(mockChannel); // Animations are disabled Settings.Global.putFloat(mockContentResolver, "transition_animation_scale", 0.0f); observer.onChange(false); - verify(mockChannel) - .setAccessibilityFeatures( - ACCESSIBILITY_FEATURE_DISABLE_ANIMATIONS | ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + verify(mockChannel).setAccessibilityFeatures(1 << 2); reset(mockChannel); // Animations are enabled Settings.Global.putFloat(mockContentResolver, "transition_animation_scale", 1.0f); observer.onChange(false); - verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + verify(mockChannel).setAccessibilityFeatures(0); } @Test diff --git a/engine/src/flutter/shell/platform/embedder/embedder.h b/engine/src/flutter/shell/platform/embedder/embedder.h index a0978917561..07f48914d22 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.h +++ b/engine/src/flutter/shell/platform/embedder/embedder.h @@ -105,8 +105,6 @@ typedef enum { kFlutterAccessibilityFeatureHighContrast = 1 << 5, /// Request to show on/off labels inside switches. kFlutterAccessibilityFeatureOnOffSwitchLabels = 1 << 6, - /// Indicate the platform does not support announcements. - kFlutterAccessibilityFeatureNoAnnounce = 1 << 7, } FlutterAccessibilityFeature; /// The set of possible actions that can be conveyed to a semantics node. diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 0afbfa05d79..b65ed44d04e 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -322,7 +322,6 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta void initState() { super.initState(); _controller = AnimationController(duration: _kTransitionDuration, vsync: this); - // TODO(ash2moon): https://github.com/flutter/flutter/issues/168022 if (_hasError) { _error = _buildError(); _controller.value = 1.0; @@ -400,31 +399,26 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta Widget _buildError() { assert(widget.error != null || widget.errorText != null); - return Builder( - builder: (BuildContext context) { - return Semantics( - container: true, - liveRegion: !MediaQuery.announceOf(context), - child: FadeTransition( - opacity: _controller, - child: FractionalTranslation( - translation: Tween( - begin: const Offset(0.0, -0.25), - end: Offset.zero, - ).evaluate(_controller.view), - child: - widget.error ?? - Text( - widget.errorText!, - style: widget.errorStyle, - textAlign: widget.textAlign, - overflow: TextOverflow.ellipsis, - maxLines: widget.errorMaxLines, - ), - ), - ), - ); - }, + return Semantics( + container: true, + child: FadeTransition( + opacity: _controller, + child: FractionalTranslation( + translation: Tween( + begin: const Offset(0.0, -0.25), + end: Offset.zero, + ).evaluate(_controller.view), + child: + widget.error ?? + Text( + widget.errorText!, + style: widget.errorStyle, + textAlign: widget.textAlign, + overflow: TextOverflow.ellipsis, + maxLines: widget.errorMaxLines, + ), + ), + ), ); } @@ -3933,7 +3927,6 @@ class InputDecoration { bool? alignLabelWithHint, BoxConstraints? constraints, VisualDensity? visualDensity, - SemanticsService? semanticsService, }) { return InputDecoration( icon: icon ?? this.icon, diff --git a/packages/flutter/lib/src/semantics/semantics_service.dart b/packages/flutter/lib/src/semantics/semantics_service.dart index 49448218040..7086ee57165 100644 --- a/packages/flutter/lib/src/semantics/semantics_service.dart +++ b/packages/flutter/lib/src/semantics/semantics_service.dart @@ -7,6 +7,7 @@ library; import 'dart:ui' show TextDirection; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart' show SystemChannels; import 'semantics_event.dart' show AnnounceSemanticsEvent, Assertiveness, TooltipSemanticsEvent; @@ -33,8 +34,8 @@ abstract final class SemanticsService { /// Currently, this is only supported by the web engine and has no effect on /// other platforms. The default mode is [Assertiveness.polite]. /// - /// Not all platforms support announcements. Check to see if it is supported using - /// [MediaQuery.announceOf] before calling this method. + /// Not all platforms support announcements. Check to see if + /// [isAnnounceSupported] before calling this method. /// /// ### Android /// Android has [deprecated announcement events][1] due to its disruptive @@ -65,4 +66,12 @@ abstract final class SemanticsService { final TooltipSemanticsEvent event = TooltipSemanticsEvent(message); await SystemChannels.accessibility.send(event.toMap()); } + + /// Checks if announce is supported on the given platform. + /// + /// On Android the announce method is deprecated, therefore will return false. + /// On other platforms, this will return true. + static bool isAnnounceSupported() { + return defaultTargetPlatform != TargetPlatform.android; + } } diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 0733bd7c6df..7a8a29be5e1 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -16,7 +16,6 @@ import 'binding.dart'; import 'focus_manager.dart'; import 'focus_scope.dart'; import 'framework.dart'; -import 'media_query.dart'; import 'navigator.dart'; import 'pop_scope.dart'; import 'restoration.dart'; @@ -370,7 +369,7 @@ class FormState extends State
{ } } - if (errorMessage.isNotEmpty && MediaQuery.announceOf(context)) { + if (errorMessage.isNotEmpty) { final TextDirection directionality = Directionality.of(context); if (defaultTargetPlatform == TargetPlatform.iOS) { unawaited( diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index 6286df35114..042b6af458d 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -103,9 +103,6 @@ enum _MediaQueryAspect { /// Specifies the aspect corresponding to [MediaQueryData.boldText]. boldText, - /// Specifies the aspect corresponding to [MediaQueryData.announce]. - announce, - /// Specifies the aspect corresponding to [MediaQueryData.navigationMode]. navigationMode, @@ -213,7 +210,6 @@ class MediaQueryData { this.onOffSwitchLabels = false, this.disableAnimations = false, this.boldText = false, - this.announce = false, this.navigationMode = NavigationMode.traditional, this.gestureSettings = const DeviceGestureSettings(touchSlop: kTouchSlop), this.displayFeatures = const [], @@ -299,7 +295,6 @@ class MediaQueryData { platformData?.disableAnimations ?? view.platformDispatcher.accessibilityFeatures.disableAnimations, boldText = platformData?.boldText ?? view.platformDispatcher.accessibilityFeatures.boldText, - announce = platformData?.announce ?? view.platformDispatcher.accessibilityFeatures.announce, highContrast = platformData?.highContrast ?? view.platformDispatcher.accessibilityFeatures.highContrast, onOffSwitchLabels = @@ -589,23 +584,6 @@ class MediaQueryData { /// originates. final bool boldText; - /// Whether accessibility announcements (like [SemanticsService.announce]) - /// are allowed on the current platform. - /// - /// Returns `false` on Android, where platform announcements are deprecated - /// by the underlying platform. - /// - /// Returns `true` on all other platforms (iOS, web, desktop) where such - /// announcements are generally supported without discouragement. - /// - /// Use this flag to conditionally avoid making announcements on Android. - /// - /// See also: - /// - /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting - /// originates. - final bool announce; - /// Describes the navigation mode requested by the platform. /// /// Some user interfaces are better navigated using a directional pad (DPAD) @@ -687,7 +665,6 @@ class MediaQueryData { bool? invertColors, bool? accessibleNavigation, bool? boldText, - bool? announce, NavigationMode? navigationMode, DeviceGestureSettings? gestureSettings, List? displayFeatures, @@ -713,7 +690,6 @@ class MediaQueryData { disableAnimations: disableAnimations ?? this.disableAnimations, accessibleNavigation: accessibleNavigation ?? this.accessibleNavigation, boldText: boldText ?? this.boldText, - announce: announce ?? this.announce, navigationMode: navigationMode ?? this.navigationMode, gestureSettings: gestureSettings ?? this.gestureSettings, displayFeatures: displayFeatures ?? this.displayFeatures, @@ -916,7 +892,6 @@ class MediaQueryData { other.invertColors == invertColors && other.accessibleNavigation == accessibleNavigation && other.boldText == boldText && - other.announce == announce && other.navigationMode == navigationMode && other.gestureSettings == gestureSettings && listEquals(other.displayFeatures, displayFeatures) && @@ -1738,27 +1713,6 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { static bool? maybeBoldTextOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.boldText)?.boldText; - /// Returns the [MediaQueryData.announce] accessibility setting for the - /// nearest [MediaQuery] ancestor or false, if no such ancestor exists. - /// - /// Use of this method will cause the given [context] to rebuild any time that - /// the [MediaQueryData.announce] property of the ancestor [MediaQuery] - /// changes. - /// - /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} - static bool announceOf(BuildContext context) => maybeAnnounceOf(context) ?? false; - - /// Returns the [MediaQueryData.announce] accessibility setting for the - /// nearest [MediaQuery] ancestor or null, if no such ancestor exists. - /// - /// Use of this method will cause the given [context] to rebuild any time that - /// the [MediaQueryData.announce] property of the ancestor [MediaQuery] - /// changes. - /// - /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} - static bool? maybeAnnounceOf(BuildContext context) => - _maybeOf(context, _MediaQueryAspect.announce)?.announce; - /// Returns [MediaQueryData.navigationMode] for the nearest [MediaQuery] /// ancestor or throws an exception, if no such ancestor exists. /// @@ -1889,7 +1843,6 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { _MediaQueryAspect.disableAnimations => data.disableAnimations != oldWidget.data.disableAnimations, _MediaQueryAspect.boldText => data.boldText != oldWidget.data.boldText, - _MediaQueryAspect.announce => data.announce != oldWidget.data.announce, _MediaQueryAspect.navigationMode => data.navigationMode != oldWidget.data.navigationMode, _MediaQueryAspect.gestureSettings => diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 61283064627..3a5d8c08e77 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -8945,67 +8945,55 @@ void main() { semantics.dispose(); }); - for (final bool announce in [true, false]) { - testWidgets('InputDecoration errorText semantics (announce=$announce)', ( - WidgetTester tester, - ) async { - final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = _textEditingController(); - final Key key = UniqueKey(); + testWidgets('InputDecoration errorText semantics', (WidgetTester tester) async { + final SemanticsTester semantics = SemanticsTester(tester); + final TextEditingController controller = _textEditingController(); + final Key key = UniqueKey(); - await tester.pumpWidget( - overlay( - child: MediaQuery( - data: MediaQueryData(announce: announce), - child: TextField( - key: key, - controller: controller, - decoration: const InputDecoration( - labelText: 'label', - hintText: 'hint', - errorText: 'oh no!', - ), + await tester.pumpWidget( + overlay( + child: TextField( + key: key, + controller: controller, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + errorText: 'oh no!', + ), + ), + ), + ); + + expect( + semantics, + hasSemantics( + TestSemantics.root( + children: [ + TestSemantics.rootChild( + label: 'label', + textDirection: TextDirection.ltr, + actions: [SemanticsAction.tap, SemanticsAction.focus], + flags: [ + SemanticsFlag.isTextField, + SemanticsFlag.hasEnabledState, + SemanticsFlag.isEnabled, + ], + inputType: ui.SemanticsInputType.text, + currentValueLength: 0, + children: [ + TestSemantics(label: 'oh no!', textDirection: TextDirection.ltr), + ], ), - ), + ], ), - ); + ignoreTransform: true, + ignoreRect: true, + ignoreId: true, + ), + ); - expect( - semantics, - hasSemantics( - TestSemantics.root( - children: [ - TestSemantics.rootChild( - label: 'label', - textDirection: TextDirection.ltr, - actions: [SemanticsAction.tap, SemanticsAction.focus], - flags: [ - SemanticsFlag.isTextField, - SemanticsFlag.hasEnabledState, - SemanticsFlag.isEnabled, - ], - inputType: ui.SemanticsInputType.text, - currentValueLength: 0, - children: [ - TestSemantics( - label: 'oh no!', - textDirection: TextDirection.ltr, - flags: [if (!announce) SemanticsFlag.isLiveRegion], - ), - ], - ), - ], - ), - ignoreTransform: true, - ignoreRect: true, - ignoreId: true, - ), - ); - - semantics.dispose(); - debugDefaultTargetPlatformOverride = null; - }); - } + semantics.dispose(); + }); testWidgets('floating label does not overlap with value at large textScaleFactors', ( WidgetTester tester, diff --git a/packages/flutter/test/semantics/semantics_service_test.dart b/packages/flutter/test/semantics/semantics_service_test.dart index f741f316e5f..59c8fab6ad8 100644 --- a/packages/flutter/test/semantics/semantics_service_test.dart +++ b/packages/flutter/test/semantics/semantics_service_test.dart @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/semantics.dart'; -import 'package:flutter/services.dart' show SystemChannels; +import 'package:flutter/services.dart' show SystemChannels, TargetPlatform; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -44,4 +45,12 @@ void main() { ]), ); }); + + for (final TargetPlatform platform in TargetPlatform.values) { + test('Announce not supported on Android. (platform=$platform)', () { + debugDefaultTargetPlatformOverride = platform; + expect(SemanticsService.isAnnounceSupported(), platform != TargetPlatform.android); + debugDefaultTargetPlatformOverride = null; + }); + } } diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart index 79b88bb3146..cedc183c4b7 100644 --- a/packages/flutter/test/widgets/form_test.dart +++ b/packages/flutter/test/widgets/form_test.dart @@ -169,67 +169,50 @@ void main() { await checkErrorText(''); }); - for (final _PlatformAnnounceScenario test in <_PlatformAnnounceScenario>[ - _PlatformAnnounceScenario( - announce: false, - testName: - 'Should announce only the first error message when validate returns errors and announce = false', - ), - _PlatformAnnounceScenario( - announce: true, - testName: - 'Should not announce error message when validate returns errors and announce = true', - ), - ]) { - testWidgets(test.testName, (WidgetTester tester) async { - final GlobalKey formKey = GlobalKey(); - await tester.pumpWidget( - MaterialApp( - home: MediaQuery( - data: MediaQueryData(announce: test.announce), - child: Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: Material( - child: Form( - key: formKey, - child: Column( - children: [ - TextFormField(validator: (_) => 'First error message'), - TextFormField(validator: (_) => 'Second error message'), - ], - ), + testWidgets('Should announce only the first error message when validate returns errors', ( + WidgetTester tester, + ) async { + final GlobalKey formKey = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + home: MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Material( + child: Form( + key: formKey, + child: Column( + children: [ + TextFormField(validator: (_) => 'First error message'), + TextFormField(validator: (_) => 'Second error message'), + ], ), ), ), ), ), ), - ); - formKey.currentState!.reset(); - await tester.enterText(find.byType(TextFormField).first, ''); - await tester.pump(); + ), + ); + formKey.currentState!.reset(); + await tester.enterText(find.byType(TextFormField).first, ''); + await tester.pump(); - // Manually validate. - expect(find.text('First error message'), findsNothing); - expect(find.text('Second error message'), findsNothing); - formKey.currentState!.validate(); - await tester.pump(); - expect(find.text('First error message'), findsOneWidget); - expect(find.text('Second error message'), findsOneWidget); + // Manually validate. + expect(find.text('First error message'), findsNothing); + expect(find.text('Second error message'), findsNothing); + formKey.currentState!.validate(); + await tester.pump(); + expect(find.text('First error message'), findsOneWidget); + expect(find.text('Second error message'), findsOneWidget); - if (test.announce) { - final CapturedAccessibilityAnnouncement announcement = tester.takeAnnouncements().single; - expect(announcement.message, 'First error message'); - expect(announcement.textDirection, TextDirection.ltr); - expect(announcement.assertiveness, Assertiveness.assertive); - } else { - final CapturedAccessibilityAnnouncement? announcement = - tester.takeAnnouncements().firstOrNull; - expect(announcement, null); - } - }); - } + final CapturedAccessibilityAnnouncement announcement = tester.takeAnnouncements().single; + expect(announcement.message, 'First error message'); + expect(announcement.textDirection, TextDirection.ltr); + expect(announcement.assertiveness, Assertiveness.assertive); + }); testWidgets('isValid returns true when a field is valid', (WidgetTester tester) async { final GlobalKey> fieldKey1 = GlobalKey>(); @@ -405,7 +388,7 @@ void main() { Widget builder() { return MaterialApp( home: MediaQuery( - data: const MediaQueryData(announce: true), + data: const MediaQueryData(), child: Directionality( textDirection: TextDirection.ltr, child: Center( @@ -1632,9 +1615,3 @@ void main() { ); }); } - -class _PlatformAnnounceScenario { - _PlatformAnnounceScenario({required this.announce, required this.testName}); - final bool announce; - final String testName; -} diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index d530da3860f..8ca9fddcf8b 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -144,7 +144,6 @@ void main() { }); testWidgets('MediaQueryData.fromView is sane', (WidgetTester tester) async { - tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); final MediaQueryData data = MediaQueryData.fromView(tester.view); expect(data, hasOneLineDescription); expect(data.hashCode, equals(data.copyWith().hashCode)); @@ -155,7 +154,6 @@ void main() { expect(data.boldText, false); expect(data.highContrast, false); expect(data.onOffSwitchLabels, false); - expect(data.announce, false); expect(data.platformBrightness, Brightness.light); expect(data.gestureSettings.touchSlop, null); expect(data.displayFeatures, isEmpty); @@ -171,7 +169,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, alwaysUse24HourFormat: true, navigationMode: NavigationMode.directional, ); @@ -205,7 +202,6 @@ void main() { expect(data.boldText, platformData.boldText); expect(data.highContrast, platformData.highContrast); expect(data.onOffSwitchLabels, platformData.onOffSwitchLabels); - expect(data.announce, platformData.announce); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -259,7 +255,6 @@ void main() { data.onOffSwitchLabels, tester.platformDispatcher.accessibilityFeatures.onOffSwitchLabels, ); - expect(data.announce, tester.platformDispatcher.accessibilityFeatures.announce); expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -279,7 +274,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, alwaysUse24HourFormat: true, navigationMode: NavigationMode.directional, ); @@ -327,7 +321,6 @@ void main() { expect(data.boldText, platformData.boldText); expect(data.highContrast, platformData.highContrast); expect(data.onOffSwitchLabels, platformData.onOffSwitchLabels); - expect(data.announce, platformData.announce); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -400,7 +393,6 @@ void main() { data.onOffSwitchLabels, tester.platformDispatcher.accessibilityFeatures.onOffSwitchLabels, ); - expect(data.announce, tester.platformDispatcher.accessibilityFeatures.announce); expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -585,7 +577,6 @@ void main() { expect(copied.boldText, data.boldText); expect(copied.highContrast, data.highContrast); expect(copied.onOffSwitchLabels, data.onOffSwitchLabels); - expect(copied.announce, data.announce); expect(copied.platformBrightness, data.platformBrightness); expect(copied.gestureSettings, data.gestureSettings); expect(copied.displayFeatures, data.displayFeatures); @@ -626,7 +617,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, platformBrightness: Brightness.dark, navigationMode: NavigationMode.directional, gestureSettings: gestureSettings, @@ -646,7 +636,6 @@ void main() { expect(copied.boldText, true); expect(copied.highContrast, true); expect(copied.onOffSwitchLabels, true); - expect(copied.announce, true); expect(copied.platformBrightness, Brightness.dark); expect(copied.navigationMode, NavigationMode.directional); expect(copied.gestureSettings, gestureSettings); @@ -685,7 +674,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -722,7 +710,6 @@ void main() { expect(unpadded.boldText, true); expect(unpadded.highContrast, true); expect(unpadded.onOffSwitchLabels, true); - expect(unpadded.announce, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -761,7 +748,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -795,7 +781,6 @@ void main() { expect(unpadded.boldText, true); expect(unpadded.highContrast, true); expect(unpadded.onOffSwitchLabels, true); - expect(unpadded.announce, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -834,7 +819,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -871,7 +855,6 @@ void main() { expect(unpadded.boldText, true); expect(unpadded.highContrast, true); expect(unpadded.onOffSwitchLabels, true); - expect(unpadded.announce, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -910,7 +893,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -944,7 +926,6 @@ void main() { expect(unpadded.boldText, true); expect(unpadded.highContrast, true); expect(unpadded.onOffSwitchLabels, true); - expect(unpadded.announce, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -983,7 +964,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -1020,7 +1000,6 @@ void main() { expect(unpadded.boldText, true); expect(unpadded.highContrast, true); expect(unpadded.onOffSwitchLabels, true); - expect(unpadded.announce, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -1059,7 +1038,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -1093,7 +1071,6 @@ void main() { expect(unpadded.boldText, true); expect(unpadded.highContrast, true); expect(unpadded.onOffSwitchLabels, true); - expect(unpadded.announce, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -1198,32 +1175,6 @@ void main() { expect(insideOnOffSwitchLabels, true); }); - testWidgets('MediaQuery.announce', (WidgetTester tester) async { - late bool outsideAnnounce; - late bool insideAnnounce; - - tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); - await tester.pumpWidget( - Builder( - builder: (BuildContext context) { - outsideAnnounce = MediaQuery.announceOf(context); - return MediaQuery( - data: const MediaQueryData(announce: true), - child: Builder( - builder: (BuildContext context) { - insideAnnounce = MediaQuery.announceOf(context); - return Container(); - }, - ), - ); - }, - ), - ); - - expect(outsideAnnounce, false); - expect(insideAnnounce, true); - }); - testWidgets('MediaQuery.boldTextOf', (WidgetTester tester) async { late bool outsideBoldTextOverride; late bool insideBoldTextOverride; @@ -1363,7 +1314,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, displayFeatures: displayFeatures, ), child: Builder( @@ -1395,7 +1345,6 @@ void main() { expect(subScreenMediaQuery.boldText, true); expect(subScreenMediaQuery.highContrast, true); expect(subScreenMediaQuery.onOffSwitchLabels, true); - expect(subScreenMediaQuery.announce, true); expect(subScreenMediaQuery.displayFeatures, isEmpty); }); @@ -1442,7 +1391,6 @@ void main() { boldText: true, highContrast: true, onOffSwitchLabels: true, - announce: true, displayFeatures: displayFeatures, ), child: Builder( @@ -1480,7 +1428,6 @@ void main() { expect(subScreenMediaQuery.boldText, true); expect(subScreenMediaQuery.highContrast, true); expect(subScreenMediaQuery.onOffSwitchLabels, true); - expect(subScreenMediaQuery.announce, true); expect(subScreenMediaQuery.displayFeatures, [cutoutDisplayFeature]); }); @@ -1745,8 +1692,6 @@ void main() { MediaQuery.maybeOnOffSwitchLabelsOf, MediaQueryData(onOffSwitchLabels: true), ), - const _MediaQueryAspectCase(MediaQuery.announceOf, MediaQueryData(announce: true)), - const _MediaQueryAspectCase(MediaQuery.maybeAnnounceOf, MediaQueryData(announce: true)), const _MediaQueryAspectCase( MediaQuery.disableAnimationsOf, MediaQueryData(disableAnimations: true), diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index f2eb6f8a046..562cd1bcbe0 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -32,7 +32,6 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { this.reduceMotion = false, this.highContrast = false, this.onOffSwitchLabels = false, - this.announce = false, }); /// An instance of [AccessibilityFeatures] where all the features are enabled. @@ -44,7 +43,6 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { reduceMotion: true, highContrast: true, onOffSwitchLabels: true, - announce: true, ); @override @@ -68,9 +66,6 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { @override final bool onOffSwitchLabels; - @override - final bool announce; - @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) { @@ -83,8 +78,7 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { other.boldText == boldText && other.reduceMotion == reduceMotion && other.highContrast == highContrast && - other.onOffSwitchLabels == onOffSwitchLabels && - other.announce == announce; + other.onOffSwitchLabels == onOffSwitchLabels; } @override @@ -97,7 +91,6 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { reduceMotion, highContrast, onOffSwitchLabels, - announce, ); }