From 130944e78593f9ab776b70834e9c49290cf21b26 Mon Sep 17 00:00:00 2001 From: yaakovschectman <109111084+yaakovschectman@users.noreply.github.com> Date: Tue, 16 May 2023 13:37:12 -0400 Subject: [PATCH] Alert engine upon registering ServiceBinding (#126075) Send a platform message to the engine when the `ServiceBinding` is registered. Framework side of https://github.com/flutter/engine/pull/41733 Addresses https://github.com/flutter/flutter/issues/126033 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Greg Spencer --- .../flutter/lib/src/services/binding.dart | 9 ++++ .../lib/src/services/system_channels.dart | 4 ++ .../test/services/binding_lifecycle_test.dart | 45 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 packages/flutter/test/services/binding_lifecycle_test.dart diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart index 75e996950f..1fb401ea92 100644 --- a/packages/flutter/lib/src/services/binding.dart +++ b/packages/flutter/lib/src/services/binding.dart @@ -45,6 +45,7 @@ mixin ServicesBinding on BindingBase, SchedulerBinding { SystemChannels.platform.setMethodCallHandler(_handlePlatformMessage); TextInput.ensureInitialized(); readInitialLifecycleStateFromNativeWindow(); + initializationComplete(); } /// The current [ServicesBinding], if one has been created. @@ -415,6 +416,14 @@ mixin ServicesBinding on BindingBase, SchedulerBinding { void setSystemUiChangeCallback(SystemUiChangeCallback? callback) { _systemUiChangeCallback = callback; } + + /// Alert the engine that the binding is registered. This instructs the engine to + /// register its top level window handler on Windows. This signals that the app + /// is able to process "System.requestAppExit" signals from the engine. + @protected + Future initializationComplete() async { + await SystemChannels.platform.invokeMethod('System.initializationComplete'); + } } /// Signature for listening to changes in the [SystemUiMode]. diff --git a/packages/flutter/lib/src/services/system_channels.dart b/packages/flutter/lib/src/services/system_channels.dart index fd58eaba8e..3a65302a2d 100644 --- a/packages/flutter/lib/src/services/system_channels.dart +++ b/packages/flutter/lib/src/services/system_channels.dart @@ -133,6 +133,10 @@ abstract final class SystemChannels { /// * `System.requestAppExit`: The application has requested that it be /// terminated. See [ServicesBinding.exitApplication]. /// + /// * `System.initializationComplete`: Indicate to the engine the + /// initialization of a binding that may, among other tasks, register a + /// handler for application exit attempts. + /// /// Calls to methods that are not implemented on the shell side are ignored /// (so it is safe to call methods when the relevant plugin might be missing). static const MethodChannel platform = OptionalMethodChannel( diff --git a/packages/flutter/test/services/binding_lifecycle_test.dart b/packages/flutter/test/services/binding_lifecycle_test.dart new file mode 100644 index 0000000000..712a00ce3b --- /dev/null +++ b/packages/flutter/test/services/binding_lifecycle_test.dart @@ -0,0 +1,45 @@ +// Copyright 2014 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 'package:flutter/foundation.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +class _TestBinding extends BindingBase with SchedulerBinding, ServicesBinding { + @override + Future initializationComplete() async { + return super.initializationComplete(); + } + + @override + TestDefaultBinaryMessenger get defaultBinaryMessenger => super.defaultBinaryMessenger as TestDefaultBinaryMessenger; + + @override + TestDefaultBinaryMessenger createBinaryMessenger() { + Future keyboardHandler(ByteData? message) async { + return const StandardMethodCodec().encodeSuccessEnvelope({1:1}); + } + return TestDefaultBinaryMessenger( + super.createBinaryMessenger(), + outboundHandlers: {'flutter/keyboard': keyboardHandler}, + ); + } +} + +void main() { + final _TestBinding binding = _TestBinding(); + + test('can send message on completion of binding initialization', () async { + bool called = false; + binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall method) async { + if (method.method == 'System.initializationComplete') { + called = true; + } + return null; + }); + await binding.initializationComplete(); + expect(called, isTrue); + }); +}