From 3ece170c40d95e17727202d0db1b6714dec35c7c Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 15 Oct 2021 12:56:33 -0700 Subject: [PATCH] _CastError on Semantics copy in release mode (#91827) --- .../lib/src/widgets/editable_text.dart | 2 +- .../lib/src/widgets/text_selection.dart | 4 +- .../test/widgets/editable_text_test.dart | 45 +++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 550d44dca3..c18afc8d3b 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2712,7 +2712,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien if (hideHandles) { // Hide the handles and the toolbar. _selectionOverlay?.hide(); - } else { + } else if (_selectionOverlay?.toolbarIsVisible ?? false) { // Hide only the toolbar but not the handles. _selectionOverlay?.hideToolbar(); } diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 6b30c3a212..497c596511 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -357,7 +357,7 @@ class TextSelectionOverlay { /// Controls the fade-in and fade-out animations for the toolbar and handles. static const Duration fadeDuration = Duration(milliseconds: 150); - late AnimationController _toolbarController; + late final AnimationController _toolbarController; Animation get _toolbarOpacity => _toolbarController.view; /// Retrieve current value. @@ -496,7 +496,7 @@ class TextSelectionOverlay { void hideToolbar() { assert(_toolbar != null); _toolbarController.stop(); - _toolbar!.remove(); + _toolbar?.remove(); _toolbar = null; } diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 9261be9d36..7f28c9dd8c 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -3323,6 +3323,51 @@ void main() { semantics.dispose(); }); + + // Regression test for b/201218542. + testWidgets('copying with a11y works even when toolbar is hidden', (WidgetTester tester) async { + Future testByControls(TextSelectionControls controls) async { + final SemanticsTester semantics = SemanticsTester(tester); + final TextEditingController controller = TextEditingController(text: 'ABCDEFG'); + + await tester.pumpWidget(MaterialApp( + home: EditableText( + backgroundCursorColor: Colors.grey, + controller: controller, + focusNode: focusNode, + style: textStyle, + cursorColor: cursorColor, + selectionControls: controls, + ), + )); + await tester.tap(find.byType(EditableText)); + await tester.pump(); + + final SemanticsOwner owner = tester.binding.pipelineOwner.semanticsOwner!; + const int expectedNodeId = 5; + + expect(controller.value.selection.isCollapsed, isTrue); + + controller.selection = TextSelection( + baseOffset: 0, + extentOffset: controller.value.text.length, + ); + await tester.pump(); + + expect(find.text('Copy'), findsNothing); + + owner.performAction(expectedNodeId, SemanticsAction.copy); + expect(tester.takeException(), isNull); + expect( + (await Clipboard.getData(Clipboard.kTextPlain))!.text, + equals('ABCDEFG'), + ); + + semantics.dispose(); + } + await testByControls(materialTextSelectionControls); + await testByControls(cupertinoTextSelectionControls); + }); }); testWidgets('can set text with a11y', (WidgetTester tester) async {