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,