diff --git a/lib/ui/channel_buffers.dart b/lib/ui/channel_buffers.dart index ae9fbd78c9d7f..a8616698553a4 100644 --- a/lib/ui/channel_buffers.dart +++ b/lib/ui/channel_buffers.dart @@ -6,13 +6,18 @@ // KEEP THIS SYNCHRONIZED WITH ../web_ui/lib/channel_buffers.dart part of dart.ui; +/// Deprecated. Migrate to [ChannelCallback] instead. +/// /// Signature for [ChannelBuffers.drain]'s `callback` argument. /// /// The first argument is the data sent by the plugin. /// /// The second argument is a closure that, when called, will send messages /// back to the plugin. -// TODO(ianh): deprecate this once the framework is migrated to [ChannelCallback]. +@Deprecated( + 'Migrate to ChannelCallback instead. ' + 'This feature was deprecated after v3.11.0-20.0.pre.', +) typedef DrainChannelCallback = Future Function(ByteData? data, PlatformMessageResponseCallback callback); /// Signature for [ChannelBuffers.setListener]'s `callback` argument. @@ -377,6 +382,8 @@ class ChannelBuffers { } } + /// Deprecated. Migrate to [setListener] instead. + /// /// Remove and process all stored messages for a given channel. /// /// This should be called once a channel is prepared to handle messages @@ -384,7 +391,10 @@ class ChannelBuffers { /// /// The messages are processed by calling the given `callback`. Each message /// is processed in its own microtask. - // TODO(ianh): deprecate once framework uses [setListener]. + @Deprecated( + 'Migrate to setListener instead. ' + 'This feature was deprecated after v3.11.0-20.0.pre.', + ) Future drain(String name, DrainChannelCallback callback) async { final _Channel? channel = _channels[name]; while (channel != null && !channel._queue.isEmpty) { diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 1d479391984b3..47eb65cab3363 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -41,8 +41,13 @@ typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action /// [PlatformDispatcher.onPlatformMessage]. typedef PlatformMessageResponseCallback = void Function(ByteData? data); +/// Deprecated. Migrate to [ChannelBuffers.setListener] instead. +/// /// Signature for [PlatformDispatcher.onPlatformMessage]. -// TODO(ianh): deprecate once framework uses [ChannelBuffers.setListener]. +@Deprecated( + 'Migrate to ChannelBuffers.setListener instead. ' + 'This feature was deprecated after v3.11.0-20.0.pre.', +) typedef PlatformMessageCallback = void Function(String name, ByteData? data, PlatformMessageResponseCallback? callback); // Signature for _setNeedsReportTimings. @@ -651,6 +656,8 @@ class PlatformDispatcher { @Native(symbol: 'PlatformConfigurationNativeApi::RegisterBackgroundIsolate') external static void __registerBackgroundIsolate(int rootIsolateId); + /// Deprecated. Migrate to [ChannelBuffers.setListener] instead. + /// /// Called whenever this platform dispatcher receives a message from a /// platform-specific plugin. /// @@ -664,11 +671,17 @@ class PlatformDispatcher { /// /// The framework invokes this callback in the same zone in which the callback /// was set. - // TODO(ianh): Deprecate onPlatformMessage once the framework is moved over - // to using channel buffers exclusively. + @Deprecated( + 'Migrate to ChannelBuffers.setListener instead. ' + 'This feature was deprecated after v3.11.0-20.0.pre.', + ) PlatformMessageCallback? get onPlatformMessage => _onPlatformMessage; PlatformMessageCallback? _onPlatformMessage; Zone _onPlatformMessageZone = Zone.root; + @Deprecated( + 'Migrate to ChannelBuffers.setListener instead. ' + 'This feature was deprecated after v3.11.0-20.0.pre.', + ) set onPlatformMessage(PlatformMessageCallback? callback) { _onPlatformMessage = callback; _onPlatformMessageZone = Zone.current; diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 0b0e43d570334..689ebdd8f5c38 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -787,6 +787,8 @@ class SingletonFlutterWindow extends FlutterView { platformDispatcher.sendPlatformMessage(name, data, callback); } + /// Deprecated. Migrate to [ChannelBuffers.setListener] instead. + /// /// Called whenever this window receives a message from a platform-specific /// plugin. /// @@ -802,8 +804,15 @@ class SingletonFlutterWindow extends FlutterView { /// /// The framework invokes this callback in the same zone in which the /// callback was set. - // TODO(ianh): deprecate once framework uses [ChannelBuffers.setListener]. + @Deprecated( + 'Migrate to ChannelBuffers.setListener instead. ' + 'This feature was deprecated after v3.11.0-20.0.pre.', + ) PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage; + @Deprecated( + 'Migrate to ChannelBuffers.setListener instead. ' + 'This feature was deprecated after v3.11.0-20.0.pre.', + ) set onPlatformMessage(PlatformMessageCallback? callback) { platformDispatcher.onPlatformMessage = callback; } diff --git a/testing/dart/channel_buffers_test.dart b/testing/dart/channel_buffers_test.dart index 4a17705b74c31..4058719d5f996 100644 --- a/testing/dart/channel_buffers_test.dart +++ b/testing/dart/channel_buffers_test.dart @@ -31,6 +31,9 @@ void main() { called = true; } buffers.push(channel, data, callback); + // Ignoring the deprecated member use because we're specifically testing + // deprecated API. + // ignore: deprecated_member_use await buffers.drain(channel, (ByteData? drainedData, ui.PlatformMessageResponseCallback drainedCallback) async { expect(drainedData, equals(data)); assert(!called); @@ -52,6 +55,9 @@ void main() { // Ignoring the returned future because the completion of the drain is // communicated using the `completer`. + // Ignoring the deprecated member use because we're specifically testing + // deprecated API. + // ignore: deprecated_member_use buffers.drain(channel, (ByteData? drainedData, ui.PlatformMessageResponseCallback drainedCallback) async { log.add('callback'); completer.complete(); @@ -77,6 +83,9 @@ void main() { _resize(buffers, channel, 0); buffers.push(channel, data, callback); bool didCall = false; + // Ignoring the deprecated member use because we're specifically testing + // deprecated API. + // ignore: deprecated_member_use await buffers.drain(channel, (ByteData? drainedData, ui.PlatformMessageResponseCallback drainedCallback) async { didCall = true; }); @@ -87,6 +96,9 @@ void main() { const String channel = 'foo'; final ui.ChannelBuffers buffers = ui.ChannelBuffers(); bool didCall = false; + // Ignoring the deprecated member use because we're specifically testing + // deprecated API. + // ignore: deprecated_member_use await buffers.drain(channel, (ByteData? drainedData, ui.PlatformMessageResponseCallback drainedCallback) async { didCall = true; }); @@ -107,6 +119,9 @@ void main() { buffers.push(channel, three, callback); buffers.push(channel, four, callback); int counter = 0; + // Ignoring the deprecated member use because we're specifically testing + // deprecated API. + // ignore: deprecated_member_use await buffers.drain(channel, (ByteData? drainedData, ui.PlatformMessageResponseCallback drainedCallback) async { switch (counter) { case 0: @@ -132,6 +147,9 @@ void main() { buffers.push(channel, two, callback); _resize(buffers, channel, 1); int counter = 0; + // Ignoring the deprecated member use because we're specifically testing + // deprecated API. + // ignore: deprecated_member_use await buffers.drain(channel, (ByteData? drainedData, ui.PlatformMessageResponseCallback drainedCallback) async { switch (counter) { case 0: diff --git a/testing/dart/observatory/vmservice_methods_test.dart b/testing/dart/observatory/vmservice_methods_test.dart index 7ba1565d0a8d0..fa522b751ed09 100644 --- a/testing/dart/observatory/vmservice_methods_test.dart +++ b/testing/dart/observatory/vmservice_methods_test.dart @@ -74,12 +74,15 @@ void main() { fail('This test must not be run with --disable-vm-service.'); } - final Completer completer = Completer(); - ui.PlatformDispatcher.instance.onPlatformMessage = (String name, ByteData? data, ui.PlatformMessageResponseCallback? callback) { - final ByteBuffer buffer = data!.buffer; - final Uint8List list = buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); - completer.complete(PlatformResponse(name: name, contents: utf8.decode(list))); - }; + final Completer completer = Completer(); + ui.channelBuffers.setListener( + 'flutter/system', + (ByteData? data, ui.PlatformMessageResponseCallback callback) { + final ByteBuffer buffer = data!.buffer; + final Uint8List list = buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + completer.complete(utf8.decode(list)); + }, + ); vmService = await vmServiceConnectUri( 'ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws', @@ -94,13 +97,11 @@ void main() { expect(fontChangeResponse.type, 'Success'); expect( await completer.future, - const PlatformResponse( - name: 'flutter/system', - contents: '{"type":"fontsChange"}', - ), + '{"type":"fontsChange"}', ); } finally { await vmService?.dispose(); + ui.channelBuffers.clearListener('flutter/system'); } }); } @@ -121,22 +122,3 @@ Future getIsolateId(vms.VmService vmService) async { } return null; } - -class PlatformResponse { - const PlatformResponse({ - required this.name, - required this.contents, - }); - - final String name; - final String contents; - - @override - bool operator ==(Object other) => - other is PlatformResponse && - other.name == name && - other.contents == contents; - - @override - int get hashCode => Object.hash(name, contents); -} diff --git a/testing/dart/text_test.dart b/testing/dart/text_test.dart index db23069ce0b87..23fd1bdba8936 100644 --- a/testing/dart/text_test.dart +++ b/testing/dart/text_test.dart @@ -195,20 +195,19 @@ void testTextRange() { void testLoadFontFromList() { test('loadFontFromList will send platform message after font is loaded', () async { - final PlatformMessageCallback? oldHandler = PlatformDispatcher.instance.onPlatformMessage; - late String actualName; late String message; - PlatformDispatcher.instance.onPlatformMessage = (String name, ByteData? data, PlatformMessageResponseCallback? callback) { - assert(data != null); - actualName = name; - final Uint8List list = data!.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); - message = utf8.decode(list); - }; + channelBuffers.setListener( + 'flutter/system', + (ByteData? data, PlatformMessageResponseCallback? callback) { + assert(data != null); + final Uint8List list = data!.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + message = utf8.decode(list); + }, + ); final Uint8List fontData = Uint8List(0); await loadFontFromList(fontData, fontFamily: 'fake'); - PlatformDispatcher.instance.onPlatformMessage = oldHandler; - expect(actualName, 'flutter/system'); expect(message, '{"type":"fontsChange"}'); + channelBuffers.clearListener('flutter/system'); }); } diff --git a/testing/scenario_app/lib/main.dart b/testing/scenario_app/lib/main.dart index 06567dba20894..b7e69ad119292 100644 --- a/testing/scenario_app/lib/main.dart +++ b/testing/scenario_app/lib/main.dart @@ -17,12 +17,13 @@ void main() { // FlutterView to the _view property. assert(PlatformDispatcher.instance.implicitView != null); PlatformDispatcher.instance - ..onPlatformMessage = _handlePlatformMessage ..onBeginFrame = _onBeginFrame ..onDrawFrame = _onDrawFrame ..onMetricsChanged = _onMetricsChanged ..onPointerDataPacket = _onPointerDataPacket ..scheduleFrame(); + channelBuffers.setListener('driver', _handleDriverMessage); + channelBuffers.setListener('write_timeline', _handleWriteTimelineMessage); final FlutterView view = PlatformDispatcher.instance.implicitView!; // Asserting that this is greater than zero since this app runs on different @@ -41,7 +42,8 @@ void main() { /// The FlutterView into which the [Scenario]s will be rendered. FlutterView get _view => PlatformDispatcher.instance.implicitView!; -void _handleDriverMessage(Map call) { +void _handleDriverMessage(ByteData? data, PlatformMessageResponseCallback? callback) { + final Map call = json.decode(utf8.decode(data!.buffer.asUint8List())) as Map; final String? methodName = call['method'] as String?; switch (methodName) { case 'set_scenario': @@ -52,23 +54,9 @@ void _handleDriverMessage(Map call) { } } -Future _handlePlatformMessage( - String name, ByteData? data, PlatformMessageResponseCallback? callback) async { - if (data != null) { - print('$name = ${utf8.decode(data.buffer.asUint8List())}'); - } else { - print(name); - } - - switch (name) { - case 'driver': - _handleDriverMessage(json.decode(utf8.decode(data!.buffer.asUint8List())) as Map); - case 'write_timeline': - final String timelineData = await _getTimelineData(); - callback!(Uint8List.fromList(utf8.encode(timelineData)).buffer.asByteData()); - default: - currentScenario?.onPlatformMessage(name, data, callback); - } +Future _handleWriteTimelineMessage(ByteData? data, PlatformMessageResponseCallback? callback) async { + final String timelineData = await _getTimelineData(); + callback!(Uint8List.fromList(utf8.encode(timelineData)).buffer.asByteData()); } Future _getTimelineData() async { diff --git a/testing/scenario_app/lib/src/platform_echo_mixin.dart b/testing/scenario_app/lib/src/platform_echo_mixin.dart deleted file mode 100644 index 9e80929012113..0000000000000 --- a/testing/scenario_app/lib/src/platform_echo_mixin.dart +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:typed_data'; -import 'dart:ui'; - -import 'scenario.dart'; - -/// Echo platform messages back to the sender. -mixin PlatformEchoMixin on Scenario { - /// Handle a platform message. - @override - void onPlatformMessage( - String name, - ByteData? data, - PlatformMessageResponseCallback? callback, - ) { - view.platformDispatcher.sendPlatformMessage(name, data, null); - } -} diff --git a/testing/scenario_app/lib/src/platform_view.dart b/testing/scenario_app/lib/src/platform_view.dart index aeb9f7c7d05a0..9e3c559130224 100644 --- a/testing/scenario_app/lib/src/platform_view.dart +++ b/testing/scenario_app/lib/src/platform_view.dart @@ -422,6 +422,7 @@ class MultiPlatformViewBackgroundForegroundScenario extends Scenario required this.secondId, }) { _nextFrame = _firstFrame; + channelBuffers.setListener('flutter/lifecycle', _onPlatformMessage); } /// The platform view identifier to use for the first platform view. @@ -504,15 +505,10 @@ class MultiPlatformViewBackgroundForegroundScenario extends Scenario String _lastLifecycleState = ''; - @override - void onPlatformMessage( - String name, + void _onPlatformMessage( ByteData? data, PlatformMessageResponseCallback? callback, ) { - if (name != 'flutter/lifecycle') { - return; - } final String message = utf8.decode(data!.buffer.asUint8List()); if (_lastLifecycleState == 'AppLifecycleState.inactive' && message == 'AppLifecycleState.resumed') { @@ -522,6 +518,12 @@ class MultiPlatformViewBackgroundForegroundScenario extends Scenario _lastLifecycleState = message; } + + @override + void unmount() { + channelBuffers.clearListener('flutter/lifecycle'); + super.unmount(); + } } /// Platform view with clip rect. diff --git a/testing/scenario_app/lib/src/poppable_screen.dart b/testing/scenario_app/lib/src/poppable_screen.dart index 394aaaa247059..8f633bffbd9b7 100644 --- a/testing/scenario_app/lib/src/poppable_screen.dart +++ b/testing/scenario_app/lib/src/poppable_screen.dart @@ -2,17 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:typed_data'; import 'dart:ui'; import 'channel_util.dart'; -import 'platform_echo_mixin.dart'; import 'scenario.dart'; /// A blank page with a button that pops the page when tapped. -class PoppableScreenScenario extends Scenario with PlatformEchoMixin { +class PoppableScreenScenario extends Scenario { /// Creates the PoppableScreenScenario. - PoppableScreenScenario(super.view); + PoppableScreenScenario(super.view) { + channelBuffers.setListener('flutter/platform', _onHandlePlatformMessage); + } // Rect for the pop button. Only defined once onMetricsChanged is called. Rect? _buttonRect; @@ -79,4 +81,14 @@ class PoppableScreenScenario extends Scenario with PlatformEchoMixin { // will fail. ); } + + void _onHandlePlatformMessage(ByteData? data, PlatformMessageResponseCallback callback) { + view.platformDispatcher.sendPlatformMessage('flutter/platform', data, null); + } + + @override + void unmount() { + channelBuffers.clearListener('flutter/platform'); + super.unmount(); + } } diff --git a/testing/scenario_app/lib/src/scenario.dart b/testing/scenario_app/lib/src/scenario.dart index 6c3611b6f4e54..f44eeccac6f3f 100644 --- a/testing/scenario_app/lib/src/scenario.dart +++ b/testing/scenario_app/lib/src/scenario.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:typed_data'; import 'dart:ui'; /// A scenario to run for testing. @@ -51,14 +50,4 @@ abstract class Scenario { /// /// See [PlatformDispatcher.onPointerDataPacket]. void onPointerDataPacket(PointerDataPacket packet) {} - - /// Called by the program when an engine side platform channel message is - /// received. - /// - /// See [PlatformDispatcher.onPlatformMessage]. - void onPlatformMessage( - String name, - ByteData? data, - PlatformMessageResponseCallback? callback, - ) {} }