mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Enable dependency injection of Window instead of using static property (#27389)
This commit is contained in:
parent
3ba97da9f5
commit
92125ed38f
@ -32,8 +32,14 @@ Future<void> main() async {
|
|||||||
await tester.pump(); // Start drawer animation
|
await tester.pump(); // Start drawer animation
|
||||||
await tester.pump(const Duration(seconds: 1)); // Complete drawer animation
|
await tester.pump(const Duration(seconds: 1)); // Complete drawer animation
|
||||||
|
|
||||||
final TestViewConfiguration big = TestViewConfiguration(size: const Size(360.0, 640.0));
|
final TestViewConfiguration big = TestViewConfiguration(
|
||||||
final TestViewConfiguration small = TestViewConfiguration(size: const Size(355.0, 635.0));
|
size: const Size(360.0, 640.0),
|
||||||
|
window: RendererBinding.instance.window,
|
||||||
|
);
|
||||||
|
final TestViewConfiguration small = TestViewConfiguration(
|
||||||
|
size: const Size(355.0, 635.0),
|
||||||
|
window: RendererBinding.instance.window,
|
||||||
|
);
|
||||||
final RenderView renderView = WidgetsBinding.instance.renderView;
|
final RenderView renderView = WidgetsBinding.instance.renderView;
|
||||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmark;
|
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmark;
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ import 'dart:async';
|
|||||||
import 'dart:convert' show json;
|
import 'dart:convert' show json;
|
||||||
import 'dart:developer' as developer;
|
import 'dart:developer' as developer;
|
||||||
import 'dart:io' show exit;
|
import 'dart:io' show exit;
|
||||||
import 'dart:ui' show saveCompilationTrace;
|
// Before adding any more dart:ui imports, pleaes read the README.
|
||||||
|
import 'dart:ui' as ui show saveCompilationTrace, Window, window;
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
@ -66,6 +67,24 @@ abstract class BindingBase {
|
|||||||
static bool _debugInitialized = false;
|
static bool _debugInitialized = false;
|
||||||
static bool _debugServiceExtensionsRegistered = false;
|
static bool _debugServiceExtensionsRegistered = false;
|
||||||
|
|
||||||
|
/// The window to which this binding is bound.
|
||||||
|
///
|
||||||
|
/// A number of additional bindings are defined as extensions of [BindingBase],
|
||||||
|
/// e.g., [ServicesBinding], [RendererBinding], and [WidgetsBinding]. Each of
|
||||||
|
/// these bindings define behaviors that interact with a [ui.Window], e.g.,
|
||||||
|
/// [ServicesBinding] registers a [ui.Window.onPlatformMessage] handler, and
|
||||||
|
/// [RendererBinding] registers [ui.Window.onMetricsChanged],
|
||||||
|
/// [ui.Window.onTextScaleFactorChanged], [ui.Window.onSemanticsEnabledChanged],
|
||||||
|
/// and [ui.Window.onSemanticsAction] handlers.
|
||||||
|
///
|
||||||
|
/// Each of these other bindings could individually access a [Window] statically,
|
||||||
|
/// but that would preclude the ability to test these behaviors with a fake
|
||||||
|
/// window for verification purposes. Therefore, [BindingBase] exposes this
|
||||||
|
/// [Window] for use by other bindings. A subclass of [BindingBase], such as
|
||||||
|
/// [TestWidgetsFlutterBinding], can override this accessor to return a
|
||||||
|
/// different [Window] implementation, such as a [TestWindow].
|
||||||
|
ui.Window get window => ui.window;
|
||||||
|
|
||||||
/// The initialization method. Subclasses override this method to hook into
|
/// The initialization method. Subclasses override this method to hook into
|
||||||
/// the platform and otherwise configure their services. Subclasses must call
|
/// the platform and otherwise configure their services. Subclasses must call
|
||||||
/// "super.initInstances()".
|
/// "super.initInstances()".
|
||||||
@ -122,7 +141,7 @@ abstract class BindingBase {
|
|||||||
name: 'saveCompilationTrace',
|
name: 'saveCompilationTrace',
|
||||||
callback: (Map<String, String> parameters) async {
|
callback: (Map<String, String> parameters) async {
|
||||||
return <String, dynamic> {
|
return <String, dynamic> {
|
||||||
'value': saveCompilationTrace(),
|
'value': ui.saveCompilationTrace(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:ui' as ui show window, PointerDataPacket;
|
import 'dart:ui' as ui show PointerDataPacket;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
|
|||||||
void initInstances() {
|
void initInstances() {
|
||||||
super.initInstances();
|
super.initInstances();
|
||||||
_instance = this;
|
_instance = this;
|
||||||
ui.window.onPointerDataPacket = _handlePointerDataPacket;
|
window.onPointerDataPacket = _handlePointerDataPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -80,7 +80,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
|
|||||||
void _handlePointerDataPacket(ui.PointerDataPacket packet) {
|
void _handlePointerDataPacket(ui.PointerDataPacket packet) {
|
||||||
// We convert pointer data to logical pixels so that e.g. the touch slop can be
|
// We convert pointer data to logical pixels so that e.g. the touch slop can be
|
||||||
// defined in a device-independent manner.
|
// defined in a device-independent manner.
|
||||||
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, ui.window.devicePixelRatio));
|
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, window.devicePixelRatio));
|
||||||
if (!locked)
|
if (!locked)
|
||||||
_flushPointerEventQueue();
|
_flushPointerEventQueue();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui' as ui show window;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
@ -31,7 +30,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
|
|||||||
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
|
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
|
||||||
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
|
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
|
||||||
);
|
);
|
||||||
ui.window
|
window
|
||||||
..onMetricsChanged = handleMetricsChanged
|
..onMetricsChanged = handleMetricsChanged
|
||||||
..onTextScaleFactorChanged = handleTextScaleFactorChanged
|
..onTextScaleFactorChanged = handleTextScaleFactorChanged
|
||||||
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
|
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
|
||||||
@ -131,7 +130,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
|
|||||||
/// Called automatically when the binding is created.
|
/// Called automatically when the binding is created.
|
||||||
void initRenderView() {
|
void initRenderView() {
|
||||||
assert(renderView == null);
|
assert(renderView == null);
|
||||||
renderView = RenderView(configuration: createViewConfiguration());
|
renderView = RenderView(configuration: createViewConfiguration(), window: window);
|
||||||
renderView.scheduleInitialFrame();
|
renderView.scheduleInitialFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,9 +180,9 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
|
|||||||
/// this to force the display into 800x600 when a test is run on the device
|
/// this to force the display into 800x600 when a test is run on the device
|
||||||
/// using `flutter run`.
|
/// using `flutter run`.
|
||||||
ViewConfiguration createViewConfiguration() {
|
ViewConfiguration createViewConfiguration() {
|
||||||
final double devicePixelRatio = ui.window.devicePixelRatio;
|
final double devicePixelRatio = window.devicePixelRatio;
|
||||||
return ViewConfiguration(
|
return ViewConfiguration(
|
||||||
size: ui.window.physicalSize / devicePixelRatio,
|
size: window.physicalSize / devicePixelRatio,
|
||||||
devicePixelRatio: devicePixelRatio,
|
devicePixelRatio: devicePixelRatio,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -198,12 +197,12 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
|
|||||||
// the logical coordinates of the event location back to device pixels
|
// the logical coordinates of the event location back to device pixels
|
||||||
// here.
|
// here.
|
||||||
return renderView.layer
|
return renderView.layer
|
||||||
.find<MouseTrackerAnnotation>(offset * ui.window.devicePixelRatio);
|
.find<MouseTrackerAnnotation>(offset * window.devicePixelRatio);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleSemanticsEnabledChanged() {
|
void _handleSemanticsEnabledChanged() {
|
||||||
setSemanticsEnabled(ui.window.semanticsEnabled);
|
setSemanticsEnabled(window.semanticsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the render tree associated with this binding should produce a tree
|
/// Whether the render tree associated with this binding should produce a tree
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io' show Platform;
|
import 'dart:io' show Platform;
|
||||||
import 'dart:ui' as ui show Scene, SceneBuilder, window;
|
import 'dart:ui' as ui show Scene, SceneBuilder, Window;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -56,8 +56,10 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
|||||||
RenderView({
|
RenderView({
|
||||||
RenderBox child,
|
RenderBox child,
|
||||||
@required ViewConfiguration configuration,
|
@required ViewConfiguration configuration,
|
||||||
|
@required ui.Window window,
|
||||||
}) : assert(configuration != null),
|
}) : assert(configuration != null),
|
||||||
_configuration = configuration {
|
_configuration = configuration,
|
||||||
|
_window = window {
|
||||||
this.child = child;
|
this.child = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +84,8 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
|||||||
markNeedsLayout();
|
markNeedsLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.Window _window;
|
||||||
|
|
||||||
/// Whether Flutter should automatically compute the desired system UI.
|
/// Whether Flutter should automatically compute the desired system UI.
|
||||||
///
|
///
|
||||||
/// When this setting is enabled, Flutter will hit-test the layer tree at the
|
/// When this setting is enabled, Flutter will hit-test the layer tree at the
|
||||||
@ -195,7 +199,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
|||||||
final ui.Scene scene = layer.buildScene(builder);
|
final ui.Scene scene = layer.buildScene(builder);
|
||||||
if (automaticSystemUiAdjustment)
|
if (automaticSystemUiAdjustment)
|
||||||
_updateSystemChrome();
|
_updateSystemChrome();
|
||||||
ui.window.render(scene);
|
_window.render(scene);
|
||||||
scene.dispose();
|
scene.dispose();
|
||||||
assert(() {
|
assert(() {
|
||||||
if (debugRepaintRainbowEnabled || debugRepaintTextRainbowEnabled)
|
if (debugRepaintRainbowEnabled || debugRepaintTextRainbowEnabled)
|
||||||
@ -209,8 +213,8 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
|||||||
|
|
||||||
void _updateSystemChrome() {
|
void _updateSystemChrome() {
|
||||||
final Rect bounds = paintBounds;
|
final Rect bounds = paintBounds;
|
||||||
final Offset top = Offset(bounds.center.dx, ui.window.padding.top / ui.window.devicePixelRatio);
|
final Offset top = Offset(bounds.center.dx, _window.padding.top / _window.devicePixelRatio);
|
||||||
final Offset bottom = Offset(bounds.center.dx, bounds.center.dy - ui.window.padding.bottom / ui.window.devicePixelRatio);
|
final Offset bottom = Offset(bounds.center.dx, bounds.center.dy - _window.padding.bottom / _window.devicePixelRatio);
|
||||||
final SystemUiOverlayStyle upperOverlayStyle = layer.find<SystemUiOverlayStyle>(top);
|
final SystemUiOverlayStyle upperOverlayStyle = layer.find<SystemUiOverlayStyle>(top);
|
||||||
// Only android has a customizable system navigation bar.
|
// Only android has a customizable system navigation bar.
|
||||||
SystemUiOverlayStyle lowerOverlayStyle;
|
SystemUiOverlayStyle lowerOverlayStyle;
|
||||||
@ -254,10 +258,10 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
|||||||
properties.add(DiagnosticsNode.message('debug mode enabled - ${Platform.operatingSystem}'));
|
properties.add(DiagnosticsNode.message('debug mode enabled - ${Platform.operatingSystem}'));
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
properties.add(DiagnosticsProperty<Size>('window size', ui.window.physicalSize, tooltip: 'in physical pixels'));
|
properties.add(DiagnosticsProperty<Size>('window size', _window.physicalSize, tooltip: 'in physical pixels'));
|
||||||
properties.add(DoubleProperty('device pixel ratio', ui.window.devicePixelRatio, tooltip: 'physical pixels per logical pixel'));
|
properties.add(DoubleProperty('device pixel ratio', _window.devicePixelRatio, tooltip: 'physical pixels per logical pixel'));
|
||||||
properties.add(DiagnosticsProperty<ViewConfiguration>('configuration', configuration, tooltip: 'in logical pixels'));
|
properties.add(DiagnosticsProperty<ViewConfiguration>('configuration', configuration, tooltip: 'in logical pixels'));
|
||||||
if (ui.window.semanticsEnabled)
|
if (_window.semanticsEnabled)
|
||||||
properties.add(DiagnosticsNode.message('semantics enabled'));
|
properties.add(DiagnosticsNode.message('semantics enabled'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:ui' as ui show window;
|
|
||||||
import 'dart:ui' show AppLifecycleState;
|
import 'dart:ui' show AppLifecycleState;
|
||||||
|
|
||||||
import 'package:collection/collection.dart' show PriorityQueue, HeapPriorityQueue;
|
import 'package:collection/collection.dart' show PriorityQueue, HeapPriorityQueue;
|
||||||
@ -191,8 +190,8 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
|||||||
void initInstances() {
|
void initInstances() {
|
||||||
super.initInstances();
|
super.initInstances();
|
||||||
_instance = this;
|
_instance = this;
|
||||||
ui.window.onBeginFrame = _handleBeginFrame;
|
window.onBeginFrame = _handleBeginFrame;
|
||||||
ui.window.onDrawFrame = _handleDrawFrame;
|
window.onDrawFrame = _handleDrawFrame;
|
||||||
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
|
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,7 +681,7 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
|||||||
debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
|
debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
ui.window.scheduleFrame();
|
window.scheduleFrame();
|
||||||
_hasScheduledFrame = true;
|
_hasScheduledFrame = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,7 +712,7 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
|||||||
debugPrintStack(label: 'scheduleForcedFrame() called. Current phase is $schedulerPhase.');
|
debugPrintStack(label: 'scheduleForcedFrame() called. Current phase is $schedulerPhase.');
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
ui.window.scheduleFrame();
|
window.scheduleFrame();
|
||||||
_hasScheduledFrame = true;
|
_hasScheduledFrame = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:ui' as ui show AccessibilityFeatures, window;
|
import 'dart:ui' as ui show AccessibilityFeatures;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ mixin SemanticsBinding on BindingBase {
|
|||||||
void initInstances() {
|
void initInstances() {
|
||||||
super.initInstances();
|
super.initInstances();
|
||||||
_instance = this;
|
_instance = this;
|
||||||
_accessibilityFeatures = ui.window.accessibilityFeatures;
|
_accessibilityFeatures = window.accessibilityFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the platform accessibility features change.
|
/// Called when the platform accessibility features change.
|
||||||
@ -29,7 +29,7 @@ mixin SemanticsBinding on BindingBase {
|
|||||||
/// See [Window.onAccessibilityFeaturesChanged].
|
/// See [Window.onAccessibilityFeaturesChanged].
|
||||||
@protected
|
@protected
|
||||||
void handleAccessibilityFeaturesChanged() {
|
void handleAccessibilityFeaturesChanged() {
|
||||||
_accessibilityFeatures = ui.window.accessibilityFeatures;
|
_accessibilityFeatures = window.accessibilityFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The currently active set of [AccessibilityFeatures].
|
/// The currently active set of [AccessibilityFeatures].
|
||||||
|
@ -13,6 +13,7 @@ import 'package:flutter/painting.dart' show MatrixUtils, TransformProperty;
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
|
import 'binding.dart' show SemanticsBinding;
|
||||||
import 'semantics_event.dart';
|
import 'semantics_event.dart';
|
||||||
|
|
||||||
export 'dart:ui' show SemanticsAction;
|
export 'dart:ui' show SemanticsAction;
|
||||||
@ -2473,7 +2474,7 @@ class SemanticsOwner extends ChangeNotifier {
|
|||||||
final CustomSemanticsAction action = CustomSemanticsAction.getAction(actionId);
|
final CustomSemanticsAction action = CustomSemanticsAction.getAction(actionId);
|
||||||
builder.updateCustomAction(id: actionId, label: action.label, hint: action.hint, overrideId: action.action?.index ?? -1);
|
builder.updateCustomAction(id: actionId, label: action.label, hint: action.hint, overrideId: action.action?.index ?? -1);
|
||||||
}
|
}
|
||||||
ui.window.updateSemantics(builder.build());
|
SemanticsBinding.instance.window.updateSemantics(builder.build());
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ui' as ui;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
@ -20,11 +19,16 @@ mixin ServicesBinding on BindingBase {
|
|||||||
@override
|
@override
|
||||||
void initInstances() {
|
void initInstances() {
|
||||||
super.initInstances();
|
super.initInstances();
|
||||||
ui.window
|
_instance = this;
|
||||||
|
window
|
||||||
..onPlatformMessage = BinaryMessages.handlePlatformMessage;
|
..onPlatformMessage = BinaryMessages.handlePlatformMessage;
|
||||||
initLicenses();
|
initLicenses();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The current [ServicesBinding], if one has been created.
|
||||||
|
static ServicesBinding get instance => _instance;
|
||||||
|
static ServicesBinding _instance;
|
||||||
|
|
||||||
/// Adds relevant licenses to the [LicenseRegistry].
|
/// Adds relevant licenses to the [LicenseRegistry].
|
||||||
///
|
///
|
||||||
/// By default, the [ServicesBinding]'s implementation of [initLicenses] adds
|
/// By default, the [ServicesBinding]'s implementation of [initLicenses] adds
|
||||||
|
@ -8,6 +8,7 @@ import 'dart:ui' as ui;
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
import 'binding.dart' show ServicesBinding;
|
||||||
import 'platform_channel.dart';
|
import 'platform_channel.dart';
|
||||||
|
|
||||||
typedef _MessageHandler = Future<ByteData> Function(ByteData message);
|
typedef _MessageHandler = Future<ByteData> Function(ByteData message);
|
||||||
@ -36,7 +37,7 @@ class BinaryMessages {
|
|||||||
|
|
||||||
static Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
|
static Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
|
||||||
final Completer<ByteData> completer = Completer<ByteData>();
|
final Completer<ByteData> completer = Completer<ByteData>();
|
||||||
ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
|
ServicesBinding.instance.window.sendPlatformMessage(channel, message, (ByteData reply) {
|
||||||
try {
|
try {
|
||||||
completer.complete(reply);
|
completer.complete(reply);
|
||||||
} catch (exception, stack) {
|
} catch (exception, stack) {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection' show HashMap;
|
import 'dart:collection' show HashMap;
|
||||||
import 'dart:ui' as ui show window;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
@ -710,7 +709,7 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_updateNavigator();
|
_updateNavigator();
|
||||||
_locale = _resolveLocales(ui.window.locales, widget.supportedLocales);
|
_locale = _resolveLocales(WidgetsBinding.instance.window.locales, widget.supportedLocales);
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,7 +995,7 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
@override
|
@override
|
||||||
void didChangeAccessibilityFeatures() {
|
void didChangeAccessibilityFeatures() {
|
||||||
setState(() {
|
setState(() {
|
||||||
// The properties of ui.window have changed. We use them in our build
|
// The properties of window have changed. We use them in our build
|
||||||
// function, so we need setState(), but we don't cache anything locally.
|
// function, so we need setState(), but we don't cache anything locally.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1007,7 +1006,7 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
@override
|
@override
|
||||||
void didChangeMetrics() {
|
void didChangeMetrics() {
|
||||||
setState(() {
|
setState(() {
|
||||||
// The properties of ui.window have changed. We use them in our build
|
// The properties of window have changed. We use them in our build
|
||||||
// function, so we need setState(), but we don't cache anything locally.
|
// function, so we need setState(), but we don't cache anything locally.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1015,8 +1014,8 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
@override
|
@override
|
||||||
void didChangeTextScaleFactor() {
|
void didChangeTextScaleFactor() {
|
||||||
setState(() {
|
setState(() {
|
||||||
// The textScaleFactor property of ui.window has changed. We reference
|
// The textScaleFactor property of window has changed. We reference
|
||||||
// ui.window in our build function, so we need to call setState(), but
|
// window in our build function, so we need to call setState(), but
|
||||||
// we don't need to cache anything locally.
|
// we don't need to cache anything locally.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1077,12 +1076,12 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
if (_navigator != null) {
|
if (_navigator != null) {
|
||||||
navigator = Navigator(
|
navigator = Navigator(
|
||||||
key: _navigator,
|
key: _navigator,
|
||||||
// If ui.window.defaultRouteName isn't '/', we should assume it was set
|
// If window.defaultRouteName isn't '/', we should assume it was set
|
||||||
// intentionally via `setInitialRoute`, and should override whatever
|
// intentionally via `setInitialRoute`, and should override whatever
|
||||||
// is in [widget.initialRoute].
|
// is in [widget.initialRoute].
|
||||||
initialRoute: ui.window.defaultRouteName != Navigator.defaultRouteName
|
initialRoute: WidgetsBinding.instance.window.defaultRouteName != Navigator.defaultRouteName
|
||||||
? ui.window.defaultRouteName
|
? WidgetsBinding.instance.window.defaultRouteName
|
||||||
: widget.initialRoute ?? ui.window.defaultRouteName,
|
: widget.initialRoute ?? WidgetsBinding.instance.window.defaultRouteName,
|
||||||
onGenerateRoute: _onGenerateRoute,
|
onGenerateRoute: _onGenerateRoute,
|
||||||
onUnknownRoute: _onUnknownRoute,
|
onUnknownRoute: _onUnknownRoute,
|
||||||
observers: widget.navigatorObservers,
|
observers: widget.navigatorObservers,
|
||||||
@ -1183,7 +1182,7 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
assert(_debugCheckLocalizations(appLocale));
|
assert(_debugCheckLocalizations(appLocale));
|
||||||
|
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
data: MediaQueryData.fromWindow(ui.window),
|
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
|
||||||
child: Localizations(
|
child: Localizations(
|
||||||
locale: appLocale,
|
locale: appLocale,
|
||||||
delegates: _localizationsDelegates.toList(),
|
delegates: _localizationsDelegates.toList(),
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer' as developer;
|
import 'dart:developer' as developer;
|
||||||
import 'dart:ui' show AppLifecycleState, Locale, AccessibilityFeatures;
|
import 'dart:ui' show AppLifecycleState, Locale, AccessibilityFeatures;
|
||||||
import 'dart:ui' as ui show window;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
@ -141,7 +140,7 @@ abstract class WidgetsBindingObserver {
|
|||||||
///
|
///
|
||||||
/// @override
|
/// @override
|
||||||
/// void didChangeMetrics() {
|
/// void didChangeMetrics() {
|
||||||
/// setState(() { _lastSize = ui.window.physicalSize; });
|
/// setState(() { _lastSize = WidgetsBinding.instance.window.physicalSize; });
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// @override
|
/// @override
|
||||||
@ -197,7 +196,7 @@ abstract class WidgetsBindingObserver {
|
|||||||
///
|
///
|
||||||
/// @override
|
/// @override
|
||||||
/// void didChangeTextScaleFactor() {
|
/// void didChangeTextScaleFactor() {
|
||||||
/// setState(() { _lastTextScaleFactor = ui.window.textScaleFactor; });
|
/// setState(() { _lastTextScaleFactor = WidgetsBinding.instance.window.textScaleFactor; });
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// @override
|
/// @override
|
||||||
@ -250,8 +249,8 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB
|
|||||||
super.initInstances();
|
super.initInstances();
|
||||||
_instance = this;
|
_instance = this;
|
||||||
buildOwner.onBuildScheduled = _handleBuildScheduled;
|
buildOwner.onBuildScheduled = _handleBuildScheduled;
|
||||||
ui.window.onLocaleChanged = handleLocaleChanged;
|
window.onLocaleChanged = handleLocaleChanged;
|
||||||
ui.window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
|
window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
|
||||||
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
|
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
|
||||||
SystemChannels.system.setMessageHandler(_handleSystemMessage);
|
SystemChannels.system.setMessageHandler(_handleSystemMessage);
|
||||||
}
|
}
|
||||||
@ -424,7 +423,7 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB
|
|||||||
@protected
|
@protected
|
||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
void handleLocaleChanged() {
|
void handleLocaleChanged() {
|
||||||
dispatchLocalesChanged(ui.window.locales);
|
dispatchLocalesChanged(window.locales);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notify all the observers that the locale has changed (using
|
/// Notify all the observers that the locale has changed (using
|
||||||
|
@ -980,10 +980,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeMetrics() {
|
void didChangeMetrics() {
|
||||||
if (_lastBottomViewInset < ui.window.viewInsets.bottom) {
|
if (_lastBottomViewInset < WidgetsBinding.instance.window.viewInsets.bottom) {
|
||||||
_showCaretOnScreen();
|
_showCaretOnScreen();
|
||||||
}
|
}
|
||||||
_lastBottomViewInset = ui.window.viewInsets.bottom;
|
_lastBottomViewInset = WidgetsBinding.instance.window.viewInsets.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _formatAndSetValue(TextEditingValue value) {
|
void _formatAndSetValue(TextEditingValue value) {
|
||||||
@ -1102,7 +1102,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
|||||||
if (_hasFocus) {
|
if (_hasFocus) {
|
||||||
// Listen for changing viewInsets, which indicates keyboard showing up.
|
// Listen for changing viewInsets, which indicates keyboard showing up.
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
_lastBottomViewInset = ui.window.viewInsets.bottom;
|
_lastBottomViewInset = WidgetsBinding.instance.window.viewInsets.bottom;
|
||||||
_showCaretOnScreen();
|
_showCaretOnScreen();
|
||||||
if (!_value.selection.isValid) {
|
if (!_value.selection.isValid) {
|
||||||
// Place cursor at the end if the selection is invalid when we receive focus.
|
// Place cursor at the end if the selection is invalid when we receive focus.
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'dart:ui' as ui;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/physics.dart';
|
import 'package:flutter/physics.dart';
|
||||||
|
|
||||||
|
import 'binding.dart' show WidgetsBinding;
|
||||||
import 'overscroll_indicator.dart';
|
import 'overscroll_indicator.dart';
|
||||||
import 'scroll_metrics.dart';
|
import 'scroll_metrics.dart';
|
||||||
import 'scroll_simulation.dart';
|
import 'scroll_simulation.dart';
|
||||||
@ -174,8 +174,8 @@ class ScrollPhysics {
|
|||||||
static final Tolerance _kDefaultTolerance = Tolerance(
|
static final Tolerance _kDefaultTolerance = Tolerance(
|
||||||
// TODO(ianh): Handle the case of the device pixel ratio changing.
|
// TODO(ianh): Handle the case of the device pixel ratio changing.
|
||||||
// TODO(ianh): Get this from the local MediaQuery not dart:ui's window object.
|
// TODO(ianh): Get this from the local MediaQuery not dart:ui's window object.
|
||||||
velocity: 1.0 / (0.050 * ui.window.devicePixelRatio), // logical pixels per second
|
velocity: 1.0 / (0.050 * WidgetsBinding.instance.window.devicePixelRatio), // logical pixels per second
|
||||||
distance: 1.0 / ui.window.devicePixelRatio // logical pixels
|
distance: 1.0 / WidgetsBinding.instance.window.devicePixelRatio // logical pixels
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The tolerance to use for ballistic simulations.
|
/// The tolerance to use for ballistic simulations.
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'dart:ui' show SemanticsFlag;
|
import 'dart:ui' show SemanticsFlag;
|
||||||
import 'dart:ui' as ui show window;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
@ -89,7 +88,7 @@ class _SemanticsDebuggerState extends State<SemanticsDebugger> with WidgetsBindi
|
|||||||
Offset _lastPointerDownLocation;
|
Offset _lastPointerDownLocation;
|
||||||
void _handlePointerDown(PointerDownEvent event) {
|
void _handlePointerDown(PointerDownEvent event) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_lastPointerDownLocation = event.position * ui.window.devicePixelRatio;
|
_lastPointerDownLocation = event.position * WidgetsBinding.instance.window.devicePixelRatio;
|
||||||
});
|
});
|
||||||
// TODO(ianh): Use a gesture recognizer so that we can reset the
|
// TODO(ianh): Use a gesture recognizer so that we can reset the
|
||||||
// _lastPointerDownLocation when none of the other gesture recognizers win.
|
// _lastPointerDownLocation when none of the other gesture recognizers win.
|
||||||
@ -150,7 +149,7 @@ class _SemanticsDebuggerState extends State<SemanticsDebugger> with WidgetsBindi
|
|||||||
_pipelineOwner,
|
_pipelineOwner,
|
||||||
_client.generation,
|
_client.generation,
|
||||||
_lastPointerDownLocation, // in physical pixels
|
_lastPointerDownLocation, // in physical pixels
|
||||||
ui.window.devicePixelRatio,
|
WidgetsBinding.instance.window.devicePixelRatio,
|
||||||
),
|
),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
|
@ -10,7 +10,6 @@ import 'dart:math' as math;
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui' as ui
|
import 'dart:ui' as ui
|
||||||
show
|
show
|
||||||
window,
|
|
||||||
ClipOp,
|
ClipOp,
|
||||||
EngineLayer,
|
EngineLayer,
|
||||||
Image,
|
Image,
|
||||||
@ -2294,7 +2293,7 @@ class _WidgetInspectorState extends State<WidgetInspector>
|
|||||||
// on the edge of the display. If the pointer is being dragged off the edge
|
// on the edge of the display. If the pointer is being dragged off the edge
|
||||||
// of the display we do not want to select anything. A user can still select
|
// of the display we do not want to select anything. A user can still select
|
||||||
// a widget that is only at the exact screen margin by tapping.
|
// a widget that is only at the exact screen margin by tapping.
|
||||||
final Rect bounds = (Offset.zero & (ui.window.physicalSize / ui.window.devicePixelRatio)).deflate(_kOffScreenMargin);
|
final Rect bounds = (Offset.zero & (WidgetsBinding.instance.window.physicalSize / WidgetsBinding.instance.window.devicePixelRatio)).deflate(_kOffScreenMargin);
|
||||||
if (!bounds.contains(_lastPointerLocation)) {
|
if (!bounds.contains(_lastPointerLocation)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selection.clear();
|
selection.clear();
|
||||||
|
@ -44,7 +44,7 @@ void main() {
|
|||||||
expect(offscreen.child.hasSize, isFalse);
|
expect(offscreen.child.hasSize, isFalse);
|
||||||
expect(offscreen.painted, isFalse);
|
expect(offscreen.painted, isFalse);
|
||||||
// Attach the offscreen to a custom render view and owner
|
// Attach the offscreen to a custom render view and owner
|
||||||
final RenderView renderView = RenderView(configuration: testConfiguration);
|
final RenderView renderView = RenderView(configuration: testConfiguration, window: null);
|
||||||
final PipelineOwner pipelineOwner = PipelineOwner();
|
final PipelineOwner pipelineOwner = PipelineOwner();
|
||||||
renderView.attach(pipelineOwner);
|
renderView.attach(pipelineOwner);
|
||||||
renderView.child = offscreen.root;
|
renderView.child = offscreen.root;
|
||||||
@ -73,7 +73,7 @@ void main() {
|
|||||||
expect(offscreen.child.hasSize, isFalse);
|
expect(offscreen.child.hasSize, isFalse);
|
||||||
expect(offscreen.painted, isFalse);
|
expect(offscreen.painted, isFalse);
|
||||||
// Attach the offscreen to a custom render view and owner
|
// Attach the offscreen to a custom render view and owner
|
||||||
final RenderView renderView = RenderView(configuration: testConfiguration);
|
final RenderView renderView = RenderView(configuration: testConfiguration, window: null);
|
||||||
final PipelineOwner pipelineOwner = PipelineOwner();
|
final PipelineOwner pipelineOwner = PipelineOwner();
|
||||||
renderView.attach(pipelineOwner);
|
renderView.attach(pipelineOwner);
|
||||||
renderView.child = offscreen.root;
|
renderView.child = offscreen.root;
|
||||||
|
@ -4,10 +4,14 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import '../flutter_test_alternative.dart';
|
import 'package:flutter_test/src/binding.dart' show TestWidgetsFlutterBinding;
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('ensure frame is scheduled for markNeedsSemanticsUpdate', () {
|
test('ensure frame is scheduled for markNeedsSemanticsUpdate', () {
|
||||||
|
// Initialize all bindings because owner.flushSemantics() requires a window
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
final TestRenderObject renderObject = TestRenderObject();
|
final TestRenderObject renderObject = TestRenderObject();
|
||||||
int onNeedVisualUpdateCallCount = 0;
|
int onNeedVisualUpdateCallCount = 0;
|
||||||
final PipelineOwner owner = PipelineOwner(onNeedVisualUpdate: () {
|
final PipelineOwner owner = PipelineOwner(onNeedVisualUpdate: () {
|
||||||
|
@ -5,10 +5,13 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import '../flutter_test_alternative.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Mock binary message handler control test', () async {
|
test('Mock binary message handler control test', () async {
|
||||||
|
// Initialize all bindings because BinaryMessages.send() needs a window.
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
final List<ByteData> log = <ByteData>[];
|
final List<ByteData> log = <ByteData>[];
|
||||||
|
|
||||||
BinaryMessages.setMockMessageHandler('test1', (ByteData message) async {
|
BinaryMessages.setMockMessageHandler('test1', (ByteData message) async {
|
||||||
|
@ -9,7 +9,10 @@ import 'package:flutter/rendering.dart';
|
|||||||
const Size _kTestViewSize = Size(800.0, 600.0);
|
const Size _kTestViewSize = Size(800.0, 600.0);
|
||||||
|
|
||||||
class OffscreenRenderView extends RenderView {
|
class OffscreenRenderView extends RenderView {
|
||||||
OffscreenRenderView() : super(configuration: const ViewConfiguration(size: _kTestViewSize));
|
OffscreenRenderView() : super(
|
||||||
|
configuration: const ViewConfiguration(size: _kTestViewSize),
|
||||||
|
window: WidgetsBinding.instance.window,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void compositeFrame() {
|
void compositeFrame() {
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:ui' as ui;
|
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
@ -39,10 +37,10 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('MediaQueryData is sane', (WidgetTester tester) async {
|
testWidgets('MediaQueryData is sane', (WidgetTester tester) async {
|
||||||
final MediaQueryData data = MediaQueryData.fromWindow(ui.window);
|
final MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
|
||||||
expect(data, hasOneLineDescription);
|
expect(data, hasOneLineDescription);
|
||||||
expect(data.hashCode, equals(data.copyWith().hashCode));
|
expect(data.hashCode, equals(data.copyWith().hashCode));
|
||||||
expect(data.size, equals(ui.window.physicalSize / ui.window.devicePixelRatio));
|
expect(data.size, equals(WidgetsBinding.instance.window.physicalSize / WidgetsBinding.instance.window.devicePixelRatio));
|
||||||
expect(data.accessibleNavigation, false);
|
expect(data.accessibleNavigation, false);
|
||||||
expect(data.invertColors, false);
|
expect(data.invertColors, false);
|
||||||
expect(data.disableAnimations, false);
|
expect(data.disableAnimations, false);
|
||||||
@ -50,7 +48,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async {
|
testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async {
|
||||||
final MediaQueryData data = MediaQueryData.fromWindow(ui.window);
|
final MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
|
||||||
final MediaQueryData copied = data.copyWith();
|
final MediaQueryData copied = data.copyWith();
|
||||||
expect(copied.size, data.size);
|
expect(copied.size, data.size);
|
||||||
expect(copied.devicePixelRatio, data.devicePixelRatio);
|
expect(copied.devicePixelRatio, data.devicePixelRatio);
|
||||||
@ -65,7 +63,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('MediaQuery.copyWith copies specified values', (WidgetTester tester) async {
|
testWidgets('MediaQuery.copyWith copies specified values', (WidgetTester tester) async {
|
||||||
final MediaQueryData data = MediaQueryData.fromWindow(ui.window);
|
final MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
|
||||||
final MediaQueryData copied = data.copyWith(
|
final MediaQueryData copied = data.copyWith(
|
||||||
size: const Size(3.14, 2.72),
|
size: const Size(3.14, 2.72),
|
||||||
devicePixelRatio: 1.41,
|
devicePixelRatio: 1.41,
|
||||||
|
@ -62,3 +62,4 @@ export 'src/test_pointer.dart';
|
|||||||
export 'src/test_text_input.dart';
|
export 'src/test_text_input.dart';
|
||||||
export 'src/test_vsync.dart';
|
export 'src/test_vsync.dart';
|
||||||
export 'src/widget_tester.dart';
|
export 'src/widget_tester.dart';
|
||||||
|
export 'src/window.dart';
|
||||||
|
@ -108,11 +108,11 @@ class MinimumTapTargetGuideline extends AccessibilityGuideline {
|
|||||||
const double delta = 0.001;
|
const double delta = 0.001;
|
||||||
if (paintBounds.left <= delta
|
if (paintBounds.left <= delta
|
||||||
|| paintBounds.top <= delta
|
|| paintBounds.top <= delta
|
||||||
|| (paintBounds.bottom - ui.window.physicalSize.height).abs() <= delta
|
|| (paintBounds.bottom - tester.binding.window.physicalSize.height).abs() <= delta
|
||||||
|| (paintBounds.right - ui.window.physicalSize.width).abs() <= delta)
|
|| (paintBounds.right - tester.binding.window.physicalSize.width).abs() <= delta)
|
||||||
return result;
|
return result;
|
||||||
// shrink by device pixel ratio.
|
// shrink by device pixel ratio.
|
||||||
final Size candidateSize = paintBounds.size / ui.window.devicePixelRatio;
|
final Size candidateSize = paintBounds.size / tester.binding.window.devicePixelRatio;
|
||||||
if (candidateSize.width < size.width || candidateSize.height < size.height)
|
if (candidateSize.width < size.width || candidateSize.height < size.height)
|
||||||
result += Evaluation.fail(
|
result += Evaluation.fail(
|
||||||
'$node: expected tap target size of at least $size, but found $candidateSize\n'
|
'$node: expected tap target size of at least $size, but found $candidateSize\n'
|
||||||
|
@ -13,6 +13,7 @@ import 'package:flutter/rendering.dart';
|
|||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart' show TestWindow;
|
||||||
import 'package:quiver/testing/async.dart';
|
import 'package:quiver/testing/async.dart';
|
||||||
import 'package:quiver/time.dart';
|
import 'package:quiver/time.dart';
|
||||||
import 'package:test_api/test_api.dart' as test_package;
|
import 'package:test_api/test_api.dart' as test_package;
|
||||||
@ -96,12 +97,16 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
|||||||
///
|
///
|
||||||
/// This constructor overrides the [debugPrint] global hook to point to
|
/// This constructor overrides the [debugPrint] global hook to point to
|
||||||
/// [debugPrintOverride], which can be overridden by subclasses.
|
/// [debugPrintOverride], which can be overridden by subclasses.
|
||||||
TestWidgetsFlutterBinding() {
|
TestWidgetsFlutterBinding() : _window = TestWindow(window: ui.window) {
|
||||||
debugPrint = debugPrintOverride;
|
debugPrint = debugPrintOverride;
|
||||||
debugDisableShadows = disableShadows;
|
debugDisableShadows = disableShadows;
|
||||||
debugCheckIntrinsicSizes = checkIntrinsicSizes;
|
debugCheckIntrinsicSizes = checkIntrinsicSizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TestWindow get window => _window;
|
||||||
|
final TestWindow _window;
|
||||||
|
|
||||||
/// The value to set [debugPrint] to while tests are running.
|
/// The value to set [debugPrint] to while tests are running.
|
||||||
///
|
///
|
||||||
/// This can be used to redirect console output from the framework, or to
|
/// This can be used to redirect console output from the framework, or to
|
||||||
@ -265,8 +270,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
ViewConfiguration createViewConfiguration() {
|
ViewConfiguration createViewConfiguration() {
|
||||||
final double devicePixelRatio = ui.window.devicePixelRatio;
|
final double devicePixelRatio = window.devicePixelRatio;
|
||||||
final Size size = _surfaceSize ?? ui.window.physicalSize / devicePixelRatio;
|
final Size size = _surfaceSize ?? window.physicalSize / devicePixelRatio;
|
||||||
return ViewConfiguration(
|
return ViewConfiguration(
|
||||||
size: size,
|
size: size,
|
||||||
devicePixelRatio: devicePixelRatio,
|
devicePixelRatio: devicePixelRatio,
|
||||||
@ -665,8 +670,8 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
|||||||
@override
|
@override
|
||||||
void initInstances() {
|
void initInstances() {
|
||||||
super.initInstances();
|
super.initInstances();
|
||||||
ui.window.onBeginFrame = null;
|
window.onBeginFrame = null;
|
||||||
ui.window.onDrawFrame = null;
|
window.onDrawFrame = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeAsync _currentFakeAsync; // set in runTest; cleared in postTest
|
FakeAsync _currentFakeAsync; // set in runTest; cleared in postTest
|
||||||
@ -1145,7 +1150,7 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
|||||||
_pendingFrame = null;
|
_pendingFrame = null;
|
||||||
_expectingFrame = false;
|
_expectingFrame = false;
|
||||||
} else if (framePolicy != LiveTestWidgetsFlutterBindingFramePolicy.benchmark) {
|
} else if (framePolicy != LiveTestWidgetsFlutterBindingFramePolicy.benchmark) {
|
||||||
ui.window.scheduleFrame();
|
window.scheduleFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1155,6 +1160,7 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
|||||||
renderView = _LiveTestRenderView(
|
renderView = _LiveTestRenderView(
|
||||||
configuration: createViewConfiguration(),
|
configuration: createViewConfiguration(),
|
||||||
onNeedPaint: _handleViewNeedsPaint,
|
onNeedPaint: _handleViewNeedsPaint,
|
||||||
|
window: window,
|
||||||
);
|
);
|
||||||
renderView.scheduleInitialFrame();
|
renderView.scheduleInitialFrame();
|
||||||
}
|
}
|
||||||
@ -1286,7 +1292,10 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
ViewConfiguration createViewConfiguration() {
|
ViewConfiguration createViewConfiguration() {
|
||||||
return TestViewConfiguration(size: _surfaceSize ?? _kDefaultTestViewportSize);
|
return TestViewConfiguration(
|
||||||
|
size: _surfaceSize ?? _kDefaultTestViewportSize,
|
||||||
|
window: window,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1310,15 +1319,18 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
|||||||
/// size onto the actual display using the [BoxFit.contain] algorithm.
|
/// size onto the actual display using the [BoxFit.contain] algorithm.
|
||||||
class TestViewConfiguration extends ViewConfiguration {
|
class TestViewConfiguration extends ViewConfiguration {
|
||||||
/// Creates a [TestViewConfiguration] with the given size. Defaults to 800x600.
|
/// Creates a [TestViewConfiguration] with the given size. Defaults to 800x600.
|
||||||
TestViewConfiguration({ Size size = _kDefaultTestViewportSize })
|
TestViewConfiguration({
|
||||||
: _paintMatrix = _getMatrix(size, ui.window.devicePixelRatio),
|
Size size = _kDefaultTestViewportSize,
|
||||||
_hitTestMatrix = _getMatrix(size, 1.0),
|
ui.Window window,
|
||||||
|
})
|
||||||
|
: _paintMatrix = _getMatrix(size, window.devicePixelRatio, window),
|
||||||
|
_hitTestMatrix = _getMatrix(size, 1.0, window),
|
||||||
super(size: size);
|
super(size: size);
|
||||||
|
|
||||||
static Matrix4 _getMatrix(Size size, double devicePixelRatio) {
|
static Matrix4 _getMatrix(Size size, double devicePixelRatio, ui.Window window) {
|
||||||
final double inverseRatio = devicePixelRatio / ui.window.devicePixelRatio;
|
final double inverseRatio = devicePixelRatio / window.devicePixelRatio;
|
||||||
final double actualWidth = ui.window.physicalSize.width * inverseRatio;
|
final double actualWidth = window.physicalSize.width * inverseRatio;
|
||||||
final double actualHeight = ui.window.physicalSize.height * inverseRatio;
|
final double actualHeight = window.physicalSize.height * inverseRatio;
|
||||||
final double desiredWidth = size.width;
|
final double desiredWidth = size.width;
|
||||||
final double desiredHeight = size.height;
|
final double desiredHeight = size.height;
|
||||||
double scale, shiftX, shiftY;
|
double scale, shiftX, shiftY;
|
||||||
@ -1377,7 +1389,8 @@ class _LiveTestRenderView extends RenderView {
|
|||||||
_LiveTestRenderView({
|
_LiveTestRenderView({
|
||||||
ViewConfiguration configuration,
|
ViewConfiguration configuration,
|
||||||
this.onNeedPaint,
|
this.onNeedPaint,
|
||||||
}) : super(configuration: configuration);
|
@required ui.Window window,
|
||||||
|
}) : super(configuration: configuration, window: window);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TestViewConfiguration get configuration => super.configuration;
|
TestViewConfiguration get configuration => super.configuration;
|
||||||
|
303
packages/flutter_test/lib/src/window.dart
Normal file
303
packages/flutter_test/lib/src/window.dart
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
// Copyright 2018 The Chromium 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' show ByteData;
|
||||||
|
import 'dart:ui' hide window;
|
||||||
|
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
/// [Window] that wraps another [Window] and allows faking of some properties
|
||||||
|
/// for testing purposes.
|
||||||
|
///
|
||||||
|
/// Tests for certain widgets, e.g., [MaterialApp], might require faking certain
|
||||||
|
/// properties of a [Window]. [TestWindow] facilitates the faking of these properties
|
||||||
|
/// by overidding the properties of a real [Window] with desired fake values. The
|
||||||
|
/// binding used within tests, [TestWidgetsFlutterBinding], contains a [TestWindow]
|
||||||
|
/// that is used by all tests.
|
||||||
|
///
|
||||||
|
/// ## Sample Code
|
||||||
|
///
|
||||||
|
/// A test can utilize a [TestWindow] in the following way:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// testWidgets('your test name here', (WidgetTester tester) async {
|
||||||
|
/// // Retrieve the TestWidgetsFlutterBinding.
|
||||||
|
/// final TestWidgetsFlutterBinding testBinding = tester.binding;
|
||||||
|
///
|
||||||
|
/// // Fake the desired properties of the TestWindow. All code running
|
||||||
|
/// // within this test will perceive the following fake text scale
|
||||||
|
/// // factor as the real text scale factor of the window.
|
||||||
|
/// testBinding.window.textScaleFactorFakeValue = 2.5;
|
||||||
|
///
|
||||||
|
/// // Test code that depends on text scale factor here.
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The [TestWidgetsFlutterBinding] is recreated for each test and
|
||||||
|
/// therefore any fake values defined in one test will not persist
|
||||||
|
/// to the next.
|
||||||
|
///
|
||||||
|
/// If a test needs to override a real [Window] property and then later
|
||||||
|
/// return to using the real [Window] property, [TestWindow] provides
|
||||||
|
/// methods to clear each individual test value, e.g., [clearLocaleTestValue()].
|
||||||
|
///
|
||||||
|
/// To clear all fake test values in a [TestWindow], consider using [clearAllTestValues()].
|
||||||
|
class TestWindow implements Window {
|
||||||
|
/// Constructs a [TestWindow] that defers all behavior to the given [window] unless
|
||||||
|
/// explicitly overidden for test purposes.
|
||||||
|
TestWindow({
|
||||||
|
@required Window window,
|
||||||
|
}) : _window = window;
|
||||||
|
|
||||||
|
/// The [Window] that is wrapped by this [TestWindow].
|
||||||
|
final Window _window;
|
||||||
|
|
||||||
|
@override
|
||||||
|
double get devicePixelRatio => _devicePixelRatio ?? _window.devicePixelRatio;
|
||||||
|
double _devicePixelRatio;
|
||||||
|
/// Hides the real device pixel ratio and reports the given [devicePixelRatio] instead.
|
||||||
|
set devicePixelRatioTestValue(double devicePixelRatio) {
|
||||||
|
_devicePixelRatio = devicePixelRatio;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test device pixel ratio and returns to using the real device pixel ratio.
|
||||||
|
void clearDevicePixelRatioTestValue() {
|
||||||
|
_devicePixelRatio = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size get physicalSize => _physicalSizeTestValue ?? _window.physicalSize;
|
||||||
|
Size _physicalSizeTestValue;
|
||||||
|
/// Hides the real physical size and reports the given [physicalSizeTestValue] instead.
|
||||||
|
set physicalSizeTestValue (Size physicalSizeTestValue) {
|
||||||
|
_physicalSizeTestValue = physicalSizeTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test physical size and returns to using the real physical size.
|
||||||
|
void clearPhysicalSizeTestValue() {
|
||||||
|
_physicalSizeTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WindowPadding get viewInsets => _viewInsetsTestValue ?? _window.viewInsets;
|
||||||
|
WindowPadding _viewInsetsTestValue;
|
||||||
|
/// Hides the real view insets and reports the given [viewInsetsTestValue] instead.
|
||||||
|
set viewInsetsTestValue(WindowPadding viewInsetsTestValue) {
|
||||||
|
_viewInsetsTestValue = viewInsetsTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test view insets and returns to using the real view insets.
|
||||||
|
void clearViewInsetsTestValue() {
|
||||||
|
_viewInsetsTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WindowPadding get padding => _paddingTestValue ?? _window.padding;
|
||||||
|
WindowPadding _paddingTestValue;
|
||||||
|
/// Hides the real padding and reports the given [paddingTestValue] instead.
|
||||||
|
set paddingTestValue(WindowPadding paddingTestValue) {
|
||||||
|
_paddingTestValue = paddingTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test padding and returns to using the real padding.
|
||||||
|
void clearPaddingTestValue() {
|
||||||
|
_paddingTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
VoidCallback get onMetricsChanged => _window.onMetricsChanged;
|
||||||
|
@override
|
||||||
|
set onMetricsChanged(VoidCallback callback) {
|
||||||
|
_window.onMetricsChanged = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Locale get locale => _localeTestValue ?? _window.locale;
|
||||||
|
Locale _localeTestValue;
|
||||||
|
/// Hides the real locale and reports the given [localeTestValue] instead.
|
||||||
|
set localeTestValue(Locale localeTestValue) {
|
||||||
|
_localeTestValue = localeTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test locale and returns to using the real locale.
|
||||||
|
void clearLocaleTestValue() {
|
||||||
|
_localeTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Locale> get locales => _localesTestValue ?? _window.locales;
|
||||||
|
List<Locale> _localesTestValue;
|
||||||
|
/// Hides the real locales and reports the given [localesTestValue] instead.
|
||||||
|
set localesTestValue(List<Locale> localesTestValue) {
|
||||||
|
_localesTestValue = localesTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test locales and returns to using the real locales.
|
||||||
|
void clearLocalesTestValue() {
|
||||||
|
_localesTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
VoidCallback get onLocaleChanged => _window.onLocaleChanged;
|
||||||
|
@override
|
||||||
|
set onLocaleChanged(VoidCallback callback) {
|
||||||
|
_window.onLocaleChanged = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
double get textScaleFactor => _textScaleFactorTestValue ?? _window.textScaleFactor;
|
||||||
|
double _textScaleFactorTestValue;
|
||||||
|
/// Hides the real text scale factor and reports the given [textScaleFactorTestValue] instead.
|
||||||
|
set textScaleFactorTestValue(double textScaleFactorTestValue) {
|
||||||
|
_textScaleFactorTestValue = textScaleFactorTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test text scale factor and returns to using the real text scale factor.
|
||||||
|
void clearTextScaleFactorTestValue() {
|
||||||
|
_textScaleFactorTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get alwaysUse24HourFormat => _alwaysUse24HourFormatTestValue ?? _window.alwaysUse24HourFormat;
|
||||||
|
bool _alwaysUse24HourFormatTestValue;
|
||||||
|
/// Hides the real clock format and reports the given [alwaysUse24HourFormatTestValue] instead.
|
||||||
|
set alwaysUse24HourFormatTestValue(bool alwaysUse24HourFormatTestValue) {
|
||||||
|
_alwaysUse24HourFormatTestValue = alwaysUse24HourFormatTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test clock format and returns to using the real clock format.
|
||||||
|
void clearAlwaysUse24HourTestValue() {
|
||||||
|
_alwaysUse24HourFormatTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
VoidCallback get onTextScaleFactorChanged => _window.onTextScaleFactorChanged;
|
||||||
|
@override
|
||||||
|
set onTextScaleFactorChanged(VoidCallback callback) {
|
||||||
|
_window.onTextScaleFactorChanged = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FrameCallback get onBeginFrame => _window.onBeginFrame;
|
||||||
|
@override
|
||||||
|
set onBeginFrame(FrameCallback callback) {
|
||||||
|
_window.onBeginFrame = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
VoidCallback get onDrawFrame => _window.onDrawFrame;
|
||||||
|
@override
|
||||||
|
set onDrawFrame(VoidCallback callback) {
|
||||||
|
_window.onDrawFrame = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
PointerDataPacketCallback get onPointerDataPacket => _window.onPointerDataPacket;
|
||||||
|
@override
|
||||||
|
set onPointerDataPacket(PointerDataPacketCallback callback) {
|
||||||
|
_window.onPointerDataPacket = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get defaultRouteName => _defaultRouteNameTestValue ?? _window.defaultRouteName;
|
||||||
|
String _defaultRouteNameTestValue;
|
||||||
|
/// Hides the real default route name and reports the given [defaultRouteNameTestValue] instead.
|
||||||
|
set defaultRouteNameTestValue(String defaultRouteNameTestValue) {
|
||||||
|
_defaultRouteNameTestValue = defaultRouteNameTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test default route name and returns to using the real default route name.
|
||||||
|
void clearDefaultRouteNameTestValue() {
|
||||||
|
_defaultRouteNameTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void scheduleFrame() {
|
||||||
|
_window.scheduleFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void render(Scene scene) {
|
||||||
|
_window.render(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get semanticsEnabled => _semanticsEnabledTestValue ?? _window.semanticsEnabled;
|
||||||
|
bool _semanticsEnabledTestValue;
|
||||||
|
/// Hides the real semantics enabled and reports the given [semanticsEnabledTestValue] instead.
|
||||||
|
set semanticsEnabledTestValue(bool semanticsEnabledTestValue) {
|
||||||
|
_semanticsEnabledTestValue = semanticsEnabledTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test semantics enabled and returns to using the real semantics enabled.
|
||||||
|
void clearSemanticsEnabledTestValue() {
|
||||||
|
_semanticsEnabledTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
VoidCallback get onSemanticsEnabledChanged => _window.onSemanticsEnabledChanged;
|
||||||
|
@override
|
||||||
|
set onSemanticsEnabledChanged(VoidCallback callback) {
|
||||||
|
_window.onSemanticsEnabledChanged = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
SemanticsActionCallback get onSemanticsAction => _window.onSemanticsAction;
|
||||||
|
@override
|
||||||
|
set onSemanticsAction(SemanticsActionCallback callback) {
|
||||||
|
_window.onSemanticsAction = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AccessibilityFeatures get accessibilityFeatures => _accessibilityFeaturesTestValue ?? _window.accessibilityFeatures;
|
||||||
|
AccessibilityFeatures _accessibilityFeaturesTestValue;
|
||||||
|
/// Hides the real accessibility features and reports the given [accessibilityFeaturesTestValue] instead.
|
||||||
|
set accessibilityFeaturesTestValue(AccessibilityFeatures accessibilityFeaturesTestValue) {
|
||||||
|
_accessibilityFeaturesTestValue = accessibilityFeaturesTestValue;
|
||||||
|
}
|
||||||
|
/// Deletes any existing test accessibility features and returns to using the real accessibility features.
|
||||||
|
void clearAccessibilityFeaturesTestValue() {
|
||||||
|
_accessibilityFeaturesTestValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
VoidCallback get onAccessibilityFeaturesChanged => _window.onAccessibilityFeaturesChanged;
|
||||||
|
@override
|
||||||
|
set onAccessibilityFeaturesChanged(VoidCallback callback) {
|
||||||
|
_window.onAccessibilityFeaturesChanged = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updateSemantics(SemanticsUpdate update) {
|
||||||
|
_window.updateSemantics(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setIsolateDebugName(String name) {
|
||||||
|
_window.setIsolateDebugName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void sendPlatformMessage(String name,
|
||||||
|
ByteData data,
|
||||||
|
PlatformMessageResponseCallback callback) {
|
||||||
|
_window.sendPlatformMessage(name, data, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
PlatformMessageCallback get onPlatformMessage => _window.onPlatformMessage;
|
||||||
|
@override
|
||||||
|
set onPlatformMessage(PlatformMessageCallback callback) {
|
||||||
|
_window.onPlatformMessage = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete any test value properties that have been set on this [TestWindow]
|
||||||
|
/// and return to reporting the real [Window] values for all [Window] properties.
|
||||||
|
///
|
||||||
|
/// If desired, clearing of properties can be done on an individual basis, e.g.,
|
||||||
|
/// [clearLocaleTestValue()].
|
||||||
|
void clearAllTestValues() {
|
||||||
|
clearAccessibilityFeaturesTestValue();
|
||||||
|
clearAlwaysUse24HourTestValue();
|
||||||
|
clearDefaultRouteNameTestValue();
|
||||||
|
clearDevicePixelRatioTestValue();
|
||||||
|
clearLocaleTestValue();
|
||||||
|
clearLocalesTestValue();
|
||||||
|
clearPaddingTestValue();
|
||||||
|
clearPhysicalSizeTestValue();
|
||||||
|
clearSemanticsEnabledTestValue();
|
||||||
|
clearTextScaleFactorTestValue();
|
||||||
|
clearViewInsetsTestValue();
|
||||||
|
}
|
||||||
|
}
|
256
packages/flutter_test/test/window_test.dart
Normal file
256
packages/flutter_test/test/window_test.dart
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
// Copyright 2018 The Chromium 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:ui' as ui show window;
|
||||||
|
import 'dart:ui' show Size, Locale, WindowPadding, AccessibilityFeatures;
|
||||||
|
|
||||||
|
import 'package:flutter/widgets.dart' show WidgetsBinding;
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('TestWindow can fake device pixel ratio', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<double>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.devicePixelRatio,
|
||||||
|
fakeValue: 2.5,
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.devicePixelRatio;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, double fakeValue) {
|
||||||
|
binding.window.devicePixelRatioTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake physical size', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<Size>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.physicalSize,
|
||||||
|
fakeValue: const Size(50, 50),
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.physicalSize;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, Size fakeValue) {
|
||||||
|
binding.window.physicalSizeTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake view insets', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<WindowPadding>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.viewInsets,
|
||||||
|
fakeValue: const FakeWindowPadding(),
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.viewInsets;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, WindowPadding fakeValue) {
|
||||||
|
binding.window.viewInsetsTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake padding', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<WindowPadding>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.padding,
|
||||||
|
fakeValue: const FakeWindowPadding(),
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.padding;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, WindowPadding fakeValue) {
|
||||||
|
binding.window.paddingTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake locale', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<Locale>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.locale,
|
||||||
|
fakeValue: const Locale('fake_language_code'),
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.locale;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, Locale fakeValue) {
|
||||||
|
binding.window.localeTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake locales', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<List<Locale>>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.locales,
|
||||||
|
fakeValue: <Locale>[const Locale('fake_language_code')],
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.locales;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, List<Locale> fakeValue) {
|
||||||
|
binding.window.localesTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake text scale factor', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<double>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.textScaleFactor,
|
||||||
|
fakeValue: 2.5,
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.textScaleFactor;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, double fakeValue) {
|
||||||
|
binding.window.textScaleFactorTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake clock format', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<bool>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.alwaysUse24HourFormat,
|
||||||
|
fakeValue: !ui.window.alwaysUse24HourFormat,
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.alwaysUse24HourFormat;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, bool fakeValue) {
|
||||||
|
binding.window.alwaysUse24HourFormatTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake default route name', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<String>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.defaultRouteName,
|
||||||
|
fakeValue: 'fake_route',
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.defaultRouteName;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, String fakeValue) {
|
||||||
|
binding.window.defaultRouteNameTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake semantics enabled', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<bool>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.semanticsEnabled,
|
||||||
|
fakeValue: !ui.window.semanticsEnabled,
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.semanticsEnabled;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, bool fakeValue) {
|
||||||
|
binding.window.semanticsEnabledTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async {
|
||||||
|
verifyThatTestWindowCanFakeProperty<AccessibilityFeatures>(
|
||||||
|
tester: tester,
|
||||||
|
realValue: ui.window.accessibilityFeatures,
|
||||||
|
fakeValue: const FakeAccessibilityFeatures(),
|
||||||
|
propertyRetriever: () {
|
||||||
|
return WidgetsBinding.instance.window.accessibilityFeatures;
|
||||||
|
},
|
||||||
|
propertyFaker: (TestWidgetsFlutterBinding binding, AccessibilityFeatures fakeValue) {
|
||||||
|
binding.window.accessibilityFeaturesTestValue = fakeValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TestWindow can clear out fake properties all at once', (WidgetTester tester) {
|
||||||
|
final double originalDevicePixelRatio = ui.window.devicePixelRatio;
|
||||||
|
final double originalTextScaleFactor = ui.window.textScaleFactor;
|
||||||
|
final TestWindow testWindow = retrieveTestBinding(tester).window;
|
||||||
|
|
||||||
|
// Set fake values for window properties.
|
||||||
|
testWindow.devicePixelRatioTestValue = 2.5;
|
||||||
|
testWindow.textScaleFactorTestValue = 3.0;
|
||||||
|
|
||||||
|
// Erase fake window property values.
|
||||||
|
testWindow.clearAllTestValues();
|
||||||
|
|
||||||
|
// Verify that the window once again reports real property values.
|
||||||
|
expect(WidgetsBinding.instance.window.devicePixelRatio, originalDevicePixelRatio);
|
||||||
|
expect(WidgetsBinding.instance.window.textScaleFactor, originalTextScaleFactor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void verifyThatTestWindowCanFakeProperty<WindowPropertyType>({
|
||||||
|
@required WidgetTester tester,
|
||||||
|
@required WindowPropertyType realValue,
|
||||||
|
@required WindowPropertyType fakeValue,
|
||||||
|
@required WindowPropertyType Function() propertyRetriever,
|
||||||
|
@required Function(TestWidgetsFlutterBinding, WindowPropertyType fakeValue) propertyFaker,
|
||||||
|
}) {
|
||||||
|
WindowPropertyType propertyBeforeFaking;
|
||||||
|
WindowPropertyType propertyAfterFaking;
|
||||||
|
|
||||||
|
propertyBeforeFaking = propertyRetriever();
|
||||||
|
|
||||||
|
propertyFaker(retrieveTestBinding(tester), fakeValue);
|
||||||
|
|
||||||
|
propertyAfterFaking = propertyRetriever();
|
||||||
|
|
||||||
|
expect(propertyBeforeFaking, realValue);
|
||||||
|
expect(propertyAfterFaking, fakeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestWidgetsFlutterBinding retrieveTestBinding(WidgetTester tester) {
|
||||||
|
final WidgetsBinding binding = tester.binding;
|
||||||
|
assert(binding is TestWidgetsFlutterBinding);
|
||||||
|
final TestWidgetsFlutterBinding testBinding = binding;
|
||||||
|
return testBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeWindowPadding implements WindowPadding {
|
||||||
|
const FakeWindowPadding({
|
||||||
|
this.left = 0.0,
|
||||||
|
this.top = 0.0,
|
||||||
|
this.right = 0.0,
|
||||||
|
this.bottom = 0.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
final double left;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final double top;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final double right;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final double bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeAccessibilityFeatures implements AccessibilityFeatures {
|
||||||
|
const FakeAccessibilityFeatures({
|
||||||
|
this.accessibleNavigation = false,
|
||||||
|
this.invertColors = false,
|
||||||
|
this.disableAnimations = false,
|
||||||
|
this.boldText = false,
|
||||||
|
this.reduceMotion = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
final bool accessibleNavigation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final bool invertColors;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final bool disableAnimations;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final bool boldText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final bool reduceMotion;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user