diff --git a/lib/web_ui/lib/src/engine/clipboard.dart b/lib/web_ui/lib/src/engine/clipboard.dart index 0ddd34190f71c5d3938393b865f826e987a902ab..71e42bb947601ff2251245012921a047ad82ce77 100644 --- a/lib/web_ui/lib/src/engine/clipboard.dart +++ b/lib/web_ui/lib/src/engine/clipboard.dart @@ -45,12 +45,29 @@ class ClipboardMessageHandler { final Map map = {'text': data}; callback!(codec.encodeSuccessEnvelope(map)); }).catchError((dynamic error) { - print('Could not get text from clipboard: $error'); - callback!(codec.encodeErrorEnvelope( - code: 'paste_fail', message: 'Clipboard.getData failed')); + if (error is UnimplementedError) { + // Clipboard.getData not supported. + // Passing [null] to [callback] indicates that the platform message isn't + // implemented. Look at [MethodChannel.invokeMethod] to see how [null] is + // handled. + Future.delayed(Duration.zero).then((_) { + if (callback != null) { + callback(null); + } + }); + return; + } + _reportGetDataFailure(callback, codec, error); }); } + void _reportGetDataFailure(ui.PlatformMessageResponseCallback? callback, + MethodCodec codec, dynamic error) { + print('Could not get text from clipboard: $error'); + callback!(codec.encodeErrorEnvelope( + code: 'paste_fail', message: 'Clipboard.getData failed')); + } + /// Methods used by tests. set pasteFromClipboardStrategy(PasteFromClipboardStrategy strategy) { _pasteFromClipboardStrategy = strategy; @@ -185,6 +202,7 @@ class ExecCommandPasteStrategy implements PasteFromClipboardStrategy { @override Future getData() { // TODO(nurhan): https://github.com/flutter/flutter/issues/48581 - throw UnimplementedError('Paste is not implemented for this browser.'); + return Future.error( + UnimplementedError('Paste is not implemented for this browser.')); } } diff --git a/lib/web_ui/test/engine/platform_dispatcher_test.dart b/lib/web_ui/test/engine/platform_dispatcher_test.dart index 8bd86934c7312c63a2b5ca8f2d0cd98adb94adf3..c3fb5c7d5f7f6d921f0fe040e27f3a9190c9461b 100644 --- a/lib/web_ui/test/engine/platform_dispatcher_test.dart +++ b/lib/web_ui/test/engine/platform_dispatcher_test.dart @@ -3,6 +3,8 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:html' as html; +import 'dart:js_util' as js_util; import 'dart:typed_data'; import 'package:ui/src/engine.dart'; @@ -55,5 +57,31 @@ void testMain() { true, ); }); + + test('responds correctly to flutter/platform Clipboard.getData failure', + () async { + // Patch browser so that clipboard api is not available. + dynamic originalClipboard = + js_util.getProperty(html.window.navigator, 'clipboard'); + js_util.setProperty(html.window.navigator, 'clipboard', null); + const MethodCodec codec = JSONMethodCodec(); + final Completer completer = Completer(); + ui.PlatformDispatcher.instance.sendPlatformMessage( + 'flutter/platform', + codec.encodeMethodCall(MethodCall( + 'Clipboard.getData', + )), + completer.complete, + ); + final ByteData? response = await completer.future; + if (response != null) { + expect( + () => codec.decodeEnvelope(response), + throwsA(isA()), + ); + } + js_util.setProperty( + html.window.navigator, 'clipboard', originalClipboard); + }); }); }