Reverse dependency between services and scheduler (#54212)
diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart index 12a5530..37dcdd3 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart
@@ -736,8 +736,8 @@ class _RecordingWidgetsBinding extends BindingBase with GestureBinding, - ServicesBinding, SchedulerBinding, + ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding,
diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/lib/main.dart b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/lib/main.dart index 173ba34..5d6b5a6 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/lib/main.dart +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/lib/main.dart
@@ -5,7 +5,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart'; import 'package:collection/collection.dart'; @@ -48,7 +48,7 @@ super.initState(); WidgetsBinding.instance.addObserver(this); _actualLifeCycleSequence = <AppLifecycleState>[ - SchedulerBinding.instance.lifecycleState + ServicesBinding.instance.lifecycleState ]; }
diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index 957f859..126c77a 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart
@@ -6,7 +6,7 @@ import 'dart:convert' show json; import 'dart:developer' as developer; import 'dart:io' show exit; -import 'dart:ui' as ui show saveCompilationTrace, Window, window; +import 'dart:ui' as ui show AppLifecycleState, saveCompilationTrace, Window, window; // Before adding any more dart:ui imports, please read the README. import 'package:meta/meta.dart'; @@ -552,6 +552,29 @@ }); } + // TODO(goderbauer): Remove the next two members after the service/scheduler dependencies + // have been turned around. + + /// Whether the application is visible, and if so, whether it is currently + /// interactive. + /// + /// This is set by [handleAppLifecycleStateChanged] when the + /// [SystemChannels.lifecycle] notification is dispatched. + /// + /// The preferred way to watch for changes to this value is using + /// [WidgetsBindingObserver.didChangeAppLifecycleState]. + ui.AppLifecycleState get lifecycleState => null; + + /// Called when the application lifecycle state changes. + /// + /// Notifies all the observers using + /// [WidgetsBindingObserver.didChangeAppLifecycleState]. + /// + /// This method exposes notifications from [SystemChannels.lifecycle]. + @protected + @mustCallSuper + void handleAppLifecycleStateChanged(ui.AppLifecycleState state) { } + @override String toString() => '<${objectRuntimeType(this, 'BindingBase')}>'; }
diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 97d49a8..49ea361 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart
@@ -467,7 +467,7 @@ /// rendering layer directly. If you are writing to a higher-level /// library, such as the Flutter Widgets library, then you would use /// that layer's binding. -class RenderingFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, SemanticsBinding, PaintingBinding, RendererBinding { +class RenderingFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, SemanticsBinding, PaintingBinding, RendererBinding { /// Creates a binding for the rendering layer. /// /// The `root` render box is attached directly to the [renderView] and is
diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index 394c57f..3e64cfb 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart
@@ -9,7 +9,6 @@ import 'package:collection/collection.dart' show PriorityQueue, HeapPriorityQueue; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'debug.dart'; import 'priority.dart'; @@ -197,13 +196,11 @@ /// * Non-rendering tasks, to be run between frames. These are given a /// priority and are executed in priority order according to a /// [schedulingStrategy]. -mixin SchedulerBinding on BindingBase, ServicesBinding { +mixin SchedulerBinding on BindingBase { @override void initInstances() { super.initInstances(); _instance = this; - SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage); - readInitialLifecycleStateFromNativeWindow(); if (!kReleaseMode) { int frameNumber = 0; @@ -302,35 +299,19 @@ /// /// The preferred way to watch for changes to this value is using /// [WidgetsBindingObserver.didChangeAppLifecycleState]. + @override AppLifecycleState get lifecycleState => _lifecycleState; AppLifecycleState _lifecycleState; - /// Initializes the [lifecycleState] with the [initialLifecycleState] from the - /// window. - /// - /// Once the [lifecycleState] is populated through any means (including this - /// method), this method will do nothing. This is because the - /// [initialLifecycleState] may already be stale and it no longer makes sense - /// to use the initial state at dart vm startup as the current state anymore. - /// - /// The latest state should be obtained by subscribing to - /// [WidgetsBindingObserver.didChangeAppLifecycleState]. - @protected - void readInitialLifecycleStateFromNativeWindow() { - if (_lifecycleState == null && _parseAppLifecycleMessage(window.initialLifecycleState) != null) { - _handleLifecycleMessage(window.initialLifecycleState); - } - } - /// Called when the application lifecycle state changes. /// /// Notifies all the observers using /// [WidgetsBindingObserver.didChangeAppLifecycleState]. /// /// This method exposes notifications from [SystemChannels.lifecycle]. - @protected - @mustCallSuper + @override void handleAppLifecycleStateChanged(AppLifecycleState state) { + super.handleAppLifecycleStateChanged(state); assert(state != null); _lifecycleState = state; switch (state) { @@ -345,25 +326,6 @@ } } - Future<String> _handleLifecycleMessage(String message) async { - handleAppLifecycleStateChanged(_parseAppLifecycleMessage(message)); - return null; - } - - static AppLifecycleState _parseAppLifecycleMessage(String message) { - switch (message) { - case 'AppLifecycleState.paused': - return AppLifecycleState.paused; - case 'AppLifecycleState.resumed': - return AppLifecycleState.resumed; - case 'AppLifecycleState.inactive': - return AppLifecycleState.inactive; - case 'AppLifecycleState.detached': - return AppLifecycleState.detached; - } - return null; - } - /// The strategy to use when deciding whether to run a task or not. /// /// Defaults to [defaultSchedulingStrategy].
diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart index 0c4ceed..8c8a8ef 100644 --- a/packages/flutter/lib/src/services/binding.dart +++ b/packages/flutter/lib/src/services/binding.dart
@@ -7,6 +7,7 @@ import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; +import 'package:flutter/scheduler.dart'; import 'asset_bundle.dart'; import 'binary_messenger.dart'; @@ -27,6 +28,8 @@ window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage; initLicenses(); SystemChannels.system.setMessageHandler(handleSystemMessage); + SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage); + readInitialLifecycleStateFromNativeWindow(); } /// The current [ServicesBinding], if one has been created. @@ -162,6 +165,48 @@ void evict(String asset) { rootBundle.evict(asset); } + + // App life cycle + + /// Initializes the [lifecycleState] with the [initialLifecycleState] from the + /// window. + /// + /// Once the [lifecycleState] is populated through any means (including this + /// method), this method will do nothing. This is because the + /// [initialLifecycleState] may already be stale and it no longer makes sense + /// to use the initial state at dart vm startup as the current state anymore. + /// + /// The latest state should be obtained by subscribing to + /// [WidgetsBindingObserver.didChangeAppLifecycleState]. + @protected + void readInitialLifecycleStateFromNativeWindow() { + if (lifecycleState != null) { + return; + } + final AppLifecycleState state = _parseAppLifecycleMessage(window.initialLifecycleState); + if (state != null) { + handleAppLifecycleStateChanged(state); + } + } + + Future<String> _handleLifecycleMessage(String message) async { + handleAppLifecycleStateChanged(_parseAppLifecycleMessage(message)); + return null; + } + + static AppLifecycleState _parseAppLifecycleMessage(String message) { + switch (message) { + case 'AppLifecycleState.paused': + return AppLifecycleState.paused; + case 'AppLifecycleState.resumed': + return AppLifecycleState.resumed; + case 'AppLifecycleState.inactive': + return AppLifecycleState.inactive; + case 'AppLifecycleState.detached': + return AppLifecycleState.detached; + } + return null; + } } /// The default implementation of [BinaryMessenger].
diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index a8f0183..f73504d 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart
@@ -1166,7 +1166,7 @@ /// A concrete binding for applications based on the Widgets framework. /// /// This is the glue that binds the framework to the Flutter engine. -class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { +class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { /// Returns an instance of the [WidgetsBinding], creating and /// initializing it if necessary. If one is created, it will be a
diff --git a/packages/flutter/test/foundation/service_extensions_test.dart b/packages/flutter/test/foundation/service_extensions_test.dart index e0221ea..e68dd6a 100644 --- a/packages/flutter/test/foundation/service_extensions_test.dart +++ b/packages/flutter/test/foundation/service_extensions_test.dart
@@ -16,9 +16,9 @@ import '../flutter_test_alternative.dart'; class TestServiceExtensionsBinding extends BindingBase - with ServicesBinding, + with SchedulerBinding, + ServicesBinding, GestureBinding, - SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding,
diff --git a/packages/flutter/test/painting/binding_test.dart b/packages/flutter/test/painting/binding_test.dart index 74b5515..e0b8106 100644 --- a/packages/flutter/test/painting/binding_test.dart +++ b/packages/flutter/test/painting/binding_test.dart
@@ -5,6 +5,7 @@ import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/widgets.dart'; @@ -85,9 +86,15 @@ @override ui.Window get window => throw UnimplementedError(); + + @override + ui.AppLifecycleState get lifecycleState => null; + + @override + void handleAppLifecycleStateChanged(ui.AppLifecycleState state) { } } -class TestPaintingBinding extends TestBindingBase with ServicesBinding, PaintingBinding { +class TestPaintingBinding extends TestBindingBase with SchedulerBinding, ServicesBinding, PaintingBinding { @override final FakeImageCache imageCache = FakeImageCache();
diff --git a/packages/flutter/test/painting/painting_utils.dart b/packages/flutter/test/painting/painting_utils.dart index 9968bad..abcb717 100644 --- a/packages/flutter/test/painting/painting_utils.dart +++ b/packages/flutter/test/painting/painting_utils.dart
@@ -7,9 +7,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; -class PaintingBindingSpy extends BindingBase with ServicesBinding, PaintingBinding { +class PaintingBindingSpy extends BindingBase with SchedulerBinding, ServicesBinding, PaintingBinding { int counter = 0; int get instantiateImageCodecCalledCount => counter;
diff --git a/packages/flutter/test/rendering/mouse_tracking_test.dart b/packages/flutter/test/rendering/mouse_tracking_test.dart index 95753d1..89d0b05 100644 --- a/packages/flutter/test/rendering/mouse_tracking_test.dart +++ b/packages/flutter/test/rendering/mouse_tracking_test.dart
@@ -17,7 +17,7 @@ typedef HandleEventCallback = void Function(PointerEvent event); class _TestGestureFlutterBinding extends BindingBase - with ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, RendererBinding { + with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding { @override void initInstances() { super.initInstances();
diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart index dd94dfb..289c1b2 100644 --- a/packages/flutter/test/rendering/rendering_tester.dart +++ b/packages/flutter/test/rendering/rendering_tester.dart
@@ -12,7 +12,7 @@ export 'package:flutter/foundation.dart' show FlutterError, FlutterErrorDetails; export 'package:flutter_test/flutter_test.dart' show EnginePhase; -class TestRenderingFlutterBinding extends BindingBase with ServicesBinding, GestureBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding { +class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding { /// Creates a binding for testing rendering library functionality. /// /// If [onErrors] is not null, it is called if [FlutterError] caught any errors
diff --git a/packages/flutter/test/scheduler/animation_test.dart b/packages/flutter/test/scheduler/animation_test.dart index 1518e8b..441f888 100644 --- a/packages/flutter/test/scheduler/animation_test.dart +++ b/packages/flutter/test/scheduler/animation_test.dart
@@ -10,7 +10,7 @@ import 'scheduler_tester.dart'; -class TestSchedulerBinding extends BindingBase with ServicesBinding, SchedulerBinding { } +class TestSchedulerBinding extends BindingBase with SchedulerBinding, ServicesBinding { } void main() { final SchedulerBinding scheduler = TestSchedulerBinding();
diff --git a/packages/flutter/test/scheduler/scheduler_test.dart b/packages/flutter/test/scheduler/scheduler_test.dart index f7a4f19..729590f 100644 --- a/packages/flutter/test/scheduler/scheduler_test.dart +++ b/packages/flutter/test/scheduler/scheduler_test.dart
@@ -12,7 +12,7 @@ import '../flutter_test_alternative.dart'; import 'scheduler_tester.dart'; -class TestSchedulerBinding extends BindingBase with ServicesBinding, SchedulerBinding { +class TestSchedulerBinding extends BindingBase with SchedulerBinding, ServicesBinding { final Map<String, List<Map<String, dynamic>>> eventsDispatched = <String, List<Map<String, dynamic>>>{}; @override
diff --git a/packages/flutter/test/services/channel_buffers_test.dart b/packages/flutter/test/services/channel_buffers_test.dart index 4d2358a..b0e00b2 100644 --- a/packages/flutter/test/services/channel_buffers_test.dart +++ b/packages/flutter/test/services/channel_buffers_test.dart
@@ -9,10 +9,11 @@ import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -class TestChannelBuffersFlutterBinding extends BindingBase with ServicesBinding { +class TestChannelBuffersFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding { } void main() {
diff --git a/packages/flutter/test/scheduler/lifecycle_test.dart b/packages/flutter/test/services/lifecycle_test.dart similarity index 81% rename from packages/flutter/test/scheduler/lifecycle_test.dart rename to packages/flutter/test/services/lifecycle_test.dart index f5d5094..a09b982 100644 --- a/packages/flutter/test/scheduler/lifecycle_test.dart +++ b/packages/flutter/test/services/lifecycle_test.dart
@@ -3,13 +3,13 @@ // found in the LICENSE file. import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; void main() { testWidgets('initialLifecycleState is used to init state paused', (WidgetTester tester) async { // The lifecycleState is null initially in tests as there is no // initialLifecycleState. - expect(SchedulerBinding.instance.lifecycleState, equals(null)); + expect(ServicesBinding.instance.lifecycleState, equals(null)); // Mock the Window to provide paused as the AppLifecycleState final TestWidgetsFlutterBinding binding = tester.binding; // Use paused as the initial state. @@ -18,6 +18,6 @@ // The lifecycleState should now be the state we passed above, // even though no lifecycle event was fired from the platform. - expect(SchedulerBinding.instance.lifecycleState.toString(), equals('AppLifecycleState.paused')); + expect(ServicesBinding.instance.lifecycleState.toString(), equals('AppLifecycleState.paused')); }); }
diff --git a/packages/flutter_driver/lib/src/extension/extension.dart b/packages/flutter_driver/lib/src/extension/extension.dart index 6fefc2e..c7bbdcf 100644 --- a/packages/flutter_driver/lib/src/extension/extension.dart +++ b/packages/flutter_driver/lib/src/extension/extension.dart
@@ -42,7 +42,7 @@ /// eventually completes to a string response. typedef DataHandler = Future<String> Function(String message); -class _DriverBinding extends BindingBase with ServicesBinding, SchedulerBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { +class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { _DriverBinding(this._handler, this._silenceErrors); final DataHandler _handler;
diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index 7bf83aa..cfabbcb 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart
@@ -155,8 +155,8 @@ /// `HttpClient` to the code making the call, so that it can appropriately mock /// or fake responses. abstract class TestWidgetsFlutterBinding extends BindingBase - with ServicesBinding, - SchedulerBinding, + with SchedulerBinding, + ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding,