From 44e228eb9e292d1374ce03381e9e3d2c968cf002 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 7 Dec 2017 14:53:08 -0800 Subject: [PATCH] Move image logic from services/ to painting/. (#13409) This allows the scheduler library to depend on the services library and the painting library to depend on the scheduler library without the services library having to depend on the scheduler library. While I was at it I also cleaned up some of the binding logic: the licenses logic can now be overridden (and the test library does so), and the image cache can now be overridden as well. --- dev/manual_tests/test/mock_image_http.dart | 2 +- packages/flutter/lib/painting.dart | 8 ++- packages/flutter/lib/rendering.dart | 25 ++++---- packages/flutter/lib/services.dart | 5 -- .../flutter/lib/src/foundation/binding.dart | 28 ++++----- .../lib/src/material/circle_avatar.dart | 1 - packages/flutter/lib/src/material/switch.dart | 1 - .../flutter/lib/src/painting/binding.dart | 61 +++++++++++++++++++ .../lib/src/painting/box_decoration.dart | 4 +- .../flutter/lib/src/painting/decoration.dart | 4 +- .../{images.dart => decoration_image.dart} | 3 +- .../lib/src/painting/flutter_logo.dart | 2 +- .../{services => painting}/image_cache.dart | 6 -- .../{services => painting}/image_decoder.dart | 0 .../image_provider.dart | 7 +-- .../image_resolution.dart | 2 +- .../{services => painting}/image_stream.dart | 0 .../lib/src/painting/shape_decoration.dart | 4 +- .../flutter/lib/src/rendering/binding.dart | 4 +- .../flutter/lib/src/rendering/proxy_box.dart | 1 - .../flutter/lib/src/services/binding.dart | 37 ++++++++--- packages/flutter/lib/src/widgets/binding.dart | 2 +- packages/flutter/lib/src/widgets/image.dart | 12 ++-- .../flutter/lib/src/widgets/image_icon.dart | 1 - .../test/cupertino/bottom_tab_bar_test.dart | 2 +- .../flutter/test/cupertino/scaffold_test.dart | 2 +- .../test/cupertino/tab_scaffold_test.dart | 2 +- .../foundation/service_extensions_test.dart | 5 +- .../test/painting/decoration_test.dart | 8 ++- .../{services => painting}/fake_codec.dart | 0 .../fake_image_provider.dart | 2 +- .../image_cache_resize_test.dart | 7 ++- .../image_cache_test.dart | 5 +- .../{services => painting}/image_data.dart | 0 .../image_decoder_test.dart | 2 +- .../image_provider_test.dart | 2 +- .../image_stream_test.dart | 3 +- .../image_test_utils.dart | 2 +- .../mocks_for_image_cache.dart | 2 +- .../test/painting/shape_decoration_test.dart | 4 +- .../test/rendering/rendering_tester.dart | 2 +- .../test/services/asset_bundle_test.dart | 1 + .../test/widgets/fade_in_image_test.dart | 2 +- .../test/widgets/image_headers_test.dart | 2 +- .../flutter/test/widgets/image_icon_test.dart | 3 +- .../widgets/image_package_asset_test.dart | 1 - .../flutter/test/widgets/image_rtl_test.dart | 1 - packages/flutter/test/widgets/image_test.dart | 3 +- .../test/widgets/obscured_animated_image.dart | 6 +- .../lib/src/extension/extension.dart | 2 +- packages/flutter_test/lib/src/binding.dart | 9 ++- 51 files changed, 193 insertions(+), 107 deletions(-) create mode 100644 packages/flutter/lib/src/painting/binding.dart rename packages/flutter/lib/src/painting/{images.dart => decoration_image.dart} (99%) rename packages/flutter/lib/src/{services => painting}/image_cache.dart (94%) rename packages/flutter/lib/src/{services => painting}/image_decoder.dart (100%) rename packages/flutter/lib/src/{services => painting}/image_provider.dart (99%) rename packages/flutter/lib/src/{services => painting}/image_resolution.dart (99%) rename packages/flutter/lib/src/{services => painting}/image_stream.dart (100%) rename packages/flutter/test/{services => painting}/fake_codec.dart (100%) rename packages/flutter/test/{services => painting}/fake_image_provider.dart (96%) rename packages/flutter/test/{services => painting}/image_cache_resize_test.dart (88%) rename packages/flutter/test/{services => painting}/image_cache_test.dart (95%) rename packages/flutter/test/{services => painting}/image_data.dart (100%) rename packages/flutter/test/{services => painting}/image_decoder_test.dart (93%) rename packages/flutter/test/{services => painting}/image_provider_test.dart (92%) rename packages/flutter/test/{services => painting}/image_stream_test.dart (99%) rename packages/flutter/test/{services => painting}/image_test_utils.dart (97%) rename packages/flutter/test/{services => painting}/mocks_for_image_cache.dart (97%) diff --git a/dev/manual_tests/test/mock_image_http.dart b/dev/manual_tests/test/mock_image_http.dart index b491bd9a61..2ea12d8e9c 100644 --- a/dev/manual_tests/test/mock_image_http.dart +++ b/dev/manual_tests/test/mock_image_http.dart @@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart' show ValueGetter; import 'package:http/http.dart' as http; import 'package:http/testing.dart' as http; -import '../../../packages/flutter/test/services/image_data.dart'; +import '../../../packages/flutter/test/painting/image_data.dart'; // Returns a mock HTTP client that responds with an image to all requests. ValueGetter createMockImageHttpClient = () { diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart index 031a8a9c4a..dfae5c5bef 100644 --- a/packages/flutter/lib/painting.dart +++ b/packages/flutter/lib/painting.dart @@ -19,6 +19,7 @@ library painting; export 'src/painting/alignment.dart'; export 'src/painting/basic_types.dart'; +export 'src/painting/binding.dart'; export 'src/painting/border_radius.dart'; export 'src/painting/borders.dart'; export 'src/painting/box_border.dart'; @@ -28,12 +29,17 @@ export 'src/painting/box_shadow.dart'; export 'src/painting/circle_border.dart'; export 'src/painting/colors.dart'; export 'src/painting/decoration.dart'; +export 'src/painting/decoration_image.dart'; export 'src/painting/edge_insets.dart'; export 'src/painting/flutter_logo.dart'; export 'src/painting/fractional_offset.dart'; export 'src/painting/geometry.dart'; export 'src/painting/gradient.dart'; -export 'src/painting/images.dart'; +export 'src/painting/image_cache.dart'; +export 'src/painting/image_decoder.dart'; +export 'src/painting/image_provider.dart'; +export 'src/painting/image_resolution.dart'; +export 'src/painting/image_stream.dart'; export 'src/painting/matrix_utils.dart'; export 'src/painting/rounded_rectangle_border.dart'; export 'src/painting/shape_decoration.dart'; diff --git a/packages/flutter/lib/rendering.dart b/packages/flutter/lib/rendering.dart index 4e4e97d76a..979ea12436 100644 --- a/packages/flutter/lib/rendering.dart +++ b/packages/flutter/lib/rendering.dart @@ -6,20 +6,19 @@ /// /// To use, import `package:flutter/rendering.dart`. /// -/// The [RenderObject] hierarchy is used by the Flutter Widgets -/// library to implement its layout and painting back-end. Generally, -/// while you may use custom [RenderBox] classes for specific effects -/// in your applications, most of the time your only interaction with -/// the [RenderObject] hierarchy will be in debugging layout issues. +/// The [RenderObject] hierarchy is used by the Flutter Widgets library to +/// implement its layout and painting back-end. Generally, while you may use +/// custom [RenderBox] classes for specific effects in your applications, most +/// of the time your only interaction with the [RenderObject] hierarchy will be +/// in debugging layout issues. /// -/// If you are developing your own library or application directly on -/// top of the rendering library, then you will want to have a binding -/// (see [BindingBase]). You can use [RenderingFlutterBinding], or you -/// can create your own binding. If you create your own binding, it -/// needs to import at least [SchedulerBinding], [GestureBinding], -/// [ServicesBinding], and [RendererBinding]. The rendering library -/// does not automatically create a binding, but relies on one being -/// initialized with those features. +/// If you are developing your own library or application directly on top of the +/// rendering library, then you will want to have a binding (see [BindingBase]). +/// You can use [RenderingFlutterBinding], or you can create your own binding. +/// If you create your own binding, it needs to import at least +/// [ServicesBinding], [GestureBinding], [SchedulerBinding], [PaintingBinding], +/// and [RendererBinding]. The rendering library does not automatically create a +/// binding, but relies on one being initialized with those features. library rendering; export 'package:flutter/foundation.dart' show diff --git a/packages/flutter/lib/services.dart b/packages/flutter/lib/services.dart index 74e1858e69..c72fbbc22f 100644 --- a/packages/flutter/lib/services.dart +++ b/packages/flutter/lib/services.dart @@ -15,11 +15,6 @@ export 'src/services/binding.dart'; export 'src/services/clipboard.dart'; export 'src/services/haptic_feedback.dart'; export 'src/services/http_client.dart'; -export 'src/services/image_cache.dart'; -export 'src/services/image_decoder.dart'; -export 'src/services/image_provider.dart'; -export 'src/services/image_resolution.dart'; -export 'src/services/image_stream.dart'; export 'src/services/message_codec.dart'; export 'src/services/message_codecs.dart'; export 'src/services/platform_channel.dart'; diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index e0cf406282..bdaa05fdd6 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -26,19 +26,17 @@ typedef Future> ServiceExtensionCallback(Map /// "bindings"). /// /// To use this class in a mixin, inherit from it and implement -/// [initInstances()]. The mixin is guaranteed to only be constructed -/// once in the lifetime of the app (more precisely, it will assert if -/// constructed twice in checked mode). +/// [initInstances()]. The mixin is guaranteed to only be constructed once in +/// the lifetime of the app (more precisely, it will assert if constructed twice +/// in checked mode). /// -/// The top-most layer used to write the application will have a -/// concrete class that inherits from BindingBase and uses all the -/// various BindingBase mixins (such as [ServicesBinding]). For example, the -/// Widgets library in flutter introduces a binding called -/// [WidgetsFlutterBinding]. The relevant library defines how to create -/// the binding. It could be implied (for example, -/// [WidgetsFlutterBinding] is automatically started from [runApp]), or -/// the application might be required to explicitly call the -/// constructor. +/// The top-most layer used to write the application will have a concrete class +/// that inherits from [BindingBase] and uses all the various [BindingBase] +/// mixins (such as [ServicesBinding]). For example, the Widgets library in +/// Flutter introduces a binding called [WidgetsFlutterBinding]. The relevant +/// library defines how to create the binding. It could be implied (for example, +/// [WidgetsFlutterBinding] is automatically started from [runApp]), or the +/// application might be required to explicitly call the constructor. abstract class BindingBase { /// Default abstract constructor for bindings. /// @@ -106,15 +104,15 @@ abstract class BindingBase { assert(!_debugServiceExtensionsRegistered); registerSignalServiceExtension( name: 'reassemble', - callback: reassembleApplication + callback: reassembleApplication, ); registerSignalServiceExtension( name: 'exit', - callback: _exitApplication + callback: _exitApplication, ); registerSignalServiceExtension( name: 'frameworkPresent', - callback: () => new Future.value() + callback: () => new Future.value(), ); assert(() { registerServiceExtension( diff --git a/packages/flutter/lib/src/material/circle_avatar.dart b/packages/flutter/lib/src/material/circle_avatar.dart index 9bd196ade0..af9b94cdb2 100644 --- a/packages/flutter/lib/src/material/circle_avatar.dart +++ b/packages/flutter/lib/src/material/circle_avatar.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'colors.dart'; diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart index d685ae29df..35d32f4f9e 100644 --- a/packages/flutter/lib/src/material/switch.dart +++ b/packages/flutter/lib/src/material/switch.dart @@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'colors.dart'; diff --git a/packages/flutter/lib/src/painting/binding.dart b/packages/flutter/lib/src/painting/binding.dart new file mode 100644 index 0000000000..33b6c67085 --- /dev/null +++ b/packages/flutter/lib/src/painting/binding.dart @@ -0,0 +1,61 @@ +// Copyright 2016 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 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart' show ServicesBinding; + +import 'image_cache.dart'; + +/// Binding for the painting library. +/// +/// Hooks into the cache eviction logic to clear the image cache. +/// +/// Requires the [ServicesBinding] to be mixed in earlier. +abstract class PaintingBinding extends BindingBase with ServicesBinding { + // This class is intended to be used as a mixin, and should not be + // extended directly. + factory PaintingBinding._() => null; + + @override + void initInstances() { + super.initInstances(); + _instance = this; + _imageCache = createImageCache(); + } + + /// The current [PaintingBinding], if one has been created. + static PaintingBinding get instance => _instance; + static PaintingBinding _instance; + + /// The singleton that implements the Flutter framework's image cache. + /// + /// The cache is used internally by [ImageProvider] and should generally not + /// be accessed directly. + /// + /// The image cache is created during startup by the [createImageCache] + /// method. + ImageCache get imageCache => _imageCache; + ImageCache _imageCache; + + /// Creates the [ImageCache] singleton (accessible via [imageCache]). + /// + /// This method can be overridden to provide a custom image cache. + @protected + ImageCache createImageCache() => new ImageCache(); + + @override + void evict(String asset) { + super.evict(asset); + imageCache.clear(); + } +} + +/// The singleton that implements the Flutter framework's image cache. +/// +/// The cache is used internally by [ImageProvider] and should generally not be +/// accessed directly. +/// +/// The image cache is created during startup by the [PaintingBinding]'s +/// [PaintingBinding.createImageCache] method. +ImageCache get imageCache => PaintingBinding.instance.imageCache; diff --git a/packages/flutter/lib/src/painting/box_decoration.dart b/packages/flutter/lib/src/painting/box_decoration.dart index 9a401b78de..43c8a69bd7 100644 --- a/packages/flutter/lib/src/painting/box_decoration.dart +++ b/packages/flutter/lib/src/painting/box_decoration.dart @@ -5,16 +5,16 @@ import 'dart:math' as math; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'basic_types.dart'; import 'border_radius.dart'; import 'box_border.dart'; import 'box_shadow.dart'; import 'decoration.dart'; +import 'decoration_image.dart'; import 'edge_insets.dart'; import 'gradient.dart'; -import 'images.dart'; +import 'image_provider.dart'; /// An immutable description of how to paint a box. /// diff --git a/packages/flutter/lib/src/painting/decoration.dart b/packages/flutter/lib/src/painting/decoration.dart index 437cda1e00..c8b22ce39d 100644 --- a/packages/flutter/lib/src/painting/decoration.dart +++ b/packages/flutter/lib/src/painting/decoration.dart @@ -3,12 +3,10 @@ // found in the LICENSE file. import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'basic_types.dart'; import 'edge_insets.dart'; - -export 'package:flutter/services.dart' show ImageConfiguration; +import 'image_provider.dart'; // This group of classes is intended for painting in cartesian coordinates. diff --git a/packages/flutter/lib/src/painting/images.dart b/packages/flutter/lib/src/painting/decoration_image.dart similarity index 99% rename from packages/flutter/lib/src/painting/images.dart rename to packages/flutter/lib/src/painting/decoration_image.dart index 4cf5fb677b..d0f96f8672 100644 --- a/packages/flutter/lib/src/painting/images.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -5,12 +5,13 @@ import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'alignment.dart'; import 'basic_types.dart'; import 'borders.dart'; import 'box_fit.dart'; +import 'image_provider.dart'; +import 'image_stream.dart'; /// How to paint any portions of a box not covered by an image. enum ImageRepeat { diff --git a/packages/flutter/lib/src/painting/flutter_logo.dart b/packages/flutter/lib/src/painting/flutter_logo.dart index a15c62df1b..9675c4185b 100644 --- a/packages/flutter/lib/src/painting/flutter_logo.dart +++ b/packages/flutter/lib/src/painting/flutter_logo.dart @@ -6,7 +6,6 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui show Gradient, TextBox, lerpDouble; -import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart'; import 'alignment.dart'; @@ -14,6 +13,7 @@ import 'basic_types.dart'; import 'box_fit.dart'; import 'decoration.dart'; import 'edge_insets.dart'; +import 'image_provider.dart'; import 'text_painter.dart'; import 'text_span.dart'; import 'text_style.dart'; diff --git a/packages/flutter/lib/src/services/image_cache.dart b/packages/flutter/lib/src/painting/image_cache.dart similarity index 94% rename from packages/flutter/lib/src/services/image_cache.dart rename to packages/flutter/lib/src/painting/image_cache.dart index 763067f93b..1de0c03e79 100644 --- a/packages/flutter/lib/src/services/image_cache.dart +++ b/packages/flutter/lib/src/painting/image_cache.dart @@ -89,9 +89,3 @@ class ImageCache { return result; } } - -/// The singleton that implements the Flutter framework's image cache. -/// -/// The cache is used internally by [ImageProvider] and should generally not be -/// accessed directly. -final ImageCache imageCache = new ImageCache(); diff --git a/packages/flutter/lib/src/services/image_decoder.dart b/packages/flutter/lib/src/painting/image_decoder.dart similarity index 100% rename from packages/flutter/lib/src/services/image_decoder.dart rename to packages/flutter/lib/src/painting/image_decoder.dart diff --git a/packages/flutter/lib/src/services/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart similarity index 99% rename from packages/flutter/lib/src/services/image_provider.dart rename to packages/flutter/lib/src/painting/image_provider.dart index e78e54bcae..a91502e144 100644 --- a/packages/flutter/lib/src/services/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -9,11 +9,10 @@ import 'dart:ui' as ui show instantiateImageCodec, Codec; import 'dart:ui' show Size, Locale, TextDirection, hashValues; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; -import 'asset_bundle.dart'; -import 'http_client.dart'; -import 'image_cache.dart'; +import 'binding.dart'; import 'image_stream.dart'; /// Configuration information passed to the [ImageProvider.resolve] method to @@ -262,7 +261,7 @@ abstract class ImageProvider { T obtainedKey; obtainKey(configuration).then((T key) { obtainedKey = key; - stream.setCompleter(imageCache.putIfAbsent(key, () => load(key))); + stream.setCompleter(PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key))); }).catchError( (dynamic exception, StackTrace stack) async { FlutterError.reportError(new FlutterErrorDetails( diff --git a/packages/flutter/lib/src/services/image_resolution.dart b/packages/flutter/lib/src/painting/image_resolution.dart similarity index 99% rename from packages/flutter/lib/src/services/image_resolution.dart rename to packages/flutter/lib/src/painting/image_resolution.dart index d31309ecbd..75c2a15ce0 100644 --- a/packages/flutter/lib/src/services/image_resolution.dart +++ b/packages/flutter/lib/src/painting/image_resolution.dart @@ -8,8 +8,8 @@ import 'dart:convert'; import 'dart:ui' show hashValues; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; -import 'asset_bundle.dart'; import 'image_provider.dart'; const String _kAssetManifestFileName = 'AssetManifest.json'; diff --git a/packages/flutter/lib/src/services/image_stream.dart b/packages/flutter/lib/src/painting/image_stream.dart similarity index 100% rename from packages/flutter/lib/src/services/image_stream.dart rename to packages/flutter/lib/src/painting/image_stream.dart diff --git a/packages/flutter/lib/src/painting/shape_decoration.dart b/packages/flutter/lib/src/painting/shape_decoration.dart index 9e3d4707ae..f48c4eaca0 100644 --- a/packages/flutter/lib/src/painting/shape_decoration.dart +++ b/packages/flutter/lib/src/painting/shape_decoration.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'basic_types.dart'; import 'borders.dart'; @@ -12,9 +11,10 @@ import 'box_decoration.dart'; import 'box_shadow.dart'; import 'circle_border.dart'; import 'decoration.dart'; +import 'decoration_image.dart'; import 'edge_insets.dart'; import 'gradient.dart'; -import 'images.dart'; +import 'image_provider.dart'; import 'rounded_rectangle_border.dart'; /// An immutable description of how to paint an arbitrary shape. diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 25640c5a12..5b9a13710f 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -20,7 +20,7 @@ import 'view.dart'; export 'package:flutter/gestures.dart' show HitTestResult; /// The glue between the render tree and the Flutter engine. -abstract class RendererBinding extends BindingBase with SchedulerBinding, ServicesBinding, HitTestable { +abstract class RendererBinding extends BindingBase with ServicesBinding, SchedulerBinding, HitTestable { // This class is intended to be used as a mixin, and should not be // extended directly. factory RendererBinding._() => null; @@ -347,7 +347,7 @@ void debugDumpSemanticsTree(DebugSemanticsDumpOrder childOrder) { /// that layer's binding. /// /// See also [BindingBase]. -class RenderingFlutterBinding extends BindingBase with SchedulerBinding, GestureBinding, ServicesBinding, RendererBinding { +class RenderingFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, 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/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 66320f05e9..e1edd974eb 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/painting.dart'; import 'package:flutter/semantics.dart'; -import 'package:flutter/services.dart'; import 'package:vector_math/vector_math_64.dart'; diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart index 03df443847..c43af11f18 100644 --- a/packages/flutter/lib/src/services/binding.dart +++ b/packages/flutter/lib/src/services/binding.dart @@ -8,14 +8,14 @@ import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'asset_bundle.dart'; -import 'image_cache.dart'; import 'platform_messages.dart'; /// Listens for platform messages and directs them to [BinaryMessages]. /// -/// The ServicesBinding also registers a [LicenseEntryCollector] that exposes +/// The [ServicesBinding] also registers a [LicenseEntryCollector] that exposes /// the licenses found in the `LICENSE` file stored at the root of the asset -/// bundle. +/// bundle, and implements the `ext.flutter.evict` service extension (see +/// [evict]). abstract class ServicesBinding extends BindingBase { // This class is intended to be used as a mixin, and should not be // extended directly. @@ -26,6 +26,16 @@ abstract class ServicesBinding extends BindingBase { super.initInstances(); ui.window ..onPlatformMessage = BinaryMessages.handlePlatformMessage; + initLicenses(); + } + + /// Adds relevant licenses to the [LicenseRegistry]. + /// + /// By default, the [ServicesBinding]'s implementation of [initLicenses] adds + /// all the licenses collected by the `flutter` tool during compilation. + @protected + @mustCallSuper + void initLicenses() { LicenseRegistry.addLicense(_addLicenses); } @@ -51,16 +61,25 @@ abstract class ServicesBinding extends BindingBase { void initServiceExtensions() { super.initServiceExtensions(); registerStringServiceExtension( - // ext.flutter.evict value=foo.png will cause foo.png to be evicted from the rootBundle cache - // and cause the entire image cache to be cleared. This is used by hot reload mode to clear - // out the cache of resources that have changed. - // TODO(ianh): find a way to only evict affected images, not all images + // ext.flutter.evict value=foo.png will cause foo.png to be evicted from + // the rootBundle cache and cause the entire image cache to be cleared. + // This is used by hot reload mode to clear out the cache of resources + // that have changed. name: 'evict', getter: () async => '', setter: (String value) async { - rootBundle.evict(value); - imageCache.clear(); + evict(value); } ); } + + /// Called in response to the `ext.flutter.evict` service extension. + /// + /// This is used by the `flutter` tool during hot reload so that any images + /// that have changed on disk get cleared from caches. + @protected + @mustCallSuper + void evict(String asset) { + rootBundle.evict(asset); + } } diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 1f3d3a5d47..95535f11c9 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -891,7 +891,7 @@ class RenderObjectToWidgetElement extends RootRenderObje /// 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 SchedulerBinding, GestureBinding, ServicesBinding, RendererBinding, WidgetsBinding { +class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, 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/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart index 9d278cd370..bf563d4214 100644 --- a/packages/flutter/lib/src/widgets/image.dart +++ b/packages/flutter/lib/src/widgets/image.dart @@ -7,6 +7,7 @@ import 'dart:io' show File; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; +import 'package:flutter/painting.dart'; import 'package:flutter/services.dart'; import 'basic.dart'; @@ -15,13 +16,16 @@ import 'localizations.dart'; import 'media_query.dart'; import 'ticker_provider.dart'; -export 'package:flutter/services.dart' show - ImageProvider, +export 'package:flutter/painting.dart' show AssetImage, ExactAssetImage, + FileImage, + ImageConfiguration, + ImageInfo, + ImageStream, + ImageProvider, MemoryImage, - NetworkImage, - FileImage; + NetworkImage; /// Creates an [ImageConfiguration] based on the given [BuildContext] (and /// optionally size). diff --git a/packages/flutter/lib/src/widgets/image_icon.dart b/packages/flutter/lib/src/widgets/image_icon.dart index 4b67bd47fc..18fc7e0023 100644 --- a/packages/flutter/lib/src/widgets/image_icon.dart +++ b/packages/flutter/lib/src/widgets/image_icon.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; import 'basic.dart'; import 'framework.dart'; diff --git a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart index 0396bcecfd..effa4df395 100644 --- a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart +++ b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart @@ -5,7 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../services/mocks_for_image_cache.dart'; +import '../painting/mocks_for_image_cache.dart'; Future pumpWidgetWithBoilerplate(WidgetTester tester, Widget widget) async { await tester.pumpWidget( diff --git a/packages/flutter/test/cupertino/scaffold_test.dart b/packages/flutter/test/cupertino/scaffold_test.dart index ec07a84c92..a83a317806 100644 --- a/packages/flutter/test/cupertino/scaffold_test.dart +++ b/packages/flutter/test/cupertino/scaffold_test.dart @@ -5,7 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../services/mocks_for_image_cache.dart'; +import '../painting/mocks_for_image_cache.dart'; /// Integration tests testing both [CupertinoPageScaffold] and [CupertinoTabScaffold]. void main() { diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart index dcd3c7a49a..e17cd7f41a 100644 --- a/packages/flutter/test/cupertino/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart @@ -5,8 +5,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../painting/mocks_for_image_cache.dart'; import '../rendering/rendering_tester.dart'; -import '../services/mocks_for_image_cache.dart'; List selectedTabs; diff --git a/packages/flutter/test/foundation/service_extensions_test.dart b/packages/flutter/test/foundation/service_extensions_test.dart index 815b922b84..f9de7501f2 100644 --- a/packages/flutter/test/foundation/service_extensions_test.dart +++ b/packages/flutter/test/foundation/service_extensions_test.dart @@ -16,9 +16,10 @@ import 'package:flutter/widgets.dart'; import 'package:test/test.dart'; class TestServiceExtensionsBinding extends BindingBase - with SchedulerBinding, - ServicesBinding, + with ServicesBinding, GestureBinding, + SchedulerBinding, + PaintingBinding, RendererBinding, WidgetsBinding { diff --git a/packages/flutter/test/painting/decoration_test.dart b/packages/flutter/test/painting/decoration_test.dart index 039f2b8d73..c4d2314efa 100644 --- a/packages/flutter/test/painting/decoration_test.dart +++ b/packages/flutter/test/painting/decoration_test.dart @@ -7,11 +7,11 @@ import 'dart:ui' as ui show Image, ColorFilter; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; -import 'package:flutter/services.dart'; import 'package:quiver/testing/async.dart'; - import 'package:test/test.dart'; -import '../services/mocks_for_image_cache.dart'; + +import '../painting/mocks_for_image_cache.dart'; +import '../rendering/rendering_tester.dart'; class TestCanvas implements Canvas { TestCanvas([this.invocations]); @@ -90,6 +90,8 @@ class TestImage extends ui.Image { } void main() { + new TestRenderingFlutterBinding(); // initializes the imageCache + test('Decoration.lerp()', () { final BoxDecoration a = const BoxDecoration(color: const Color(0xFFFFFFFF)); final BoxDecoration b = const BoxDecoration(color: const Color(0x00000000)); diff --git a/packages/flutter/test/services/fake_codec.dart b/packages/flutter/test/painting/fake_codec.dart similarity index 100% rename from packages/flutter/test/services/fake_codec.dart rename to packages/flutter/test/painting/fake_codec.dart diff --git a/packages/flutter/test/services/fake_image_provider.dart b/packages/flutter/test/painting/fake_image_provider.dart similarity index 96% rename from packages/flutter/test/services/fake_image_provider.dart rename to packages/flutter/test/painting/fake_image_provider.dart index 71983c93a3..2a07b9cc25 100644 --- a/packages/flutter/test/services/fake_image_provider.dart +++ b/packages/flutter/test/painting/fake_image_provider.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'dart:ui' as ui show Codec; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; +import 'package:flutter/painting.dart'; /// An image provider implementation for testing that is using a [ui.Codec] /// that it was given at construction time (typically the job of real image diff --git a/packages/flutter/test/services/image_cache_resize_test.dart b/packages/flutter/test/painting/image_cache_resize_test.dart similarity index 88% rename from packages/flutter/test/services/image_cache_resize_test.dart rename to packages/flutter/test/painting/image_cache_resize_test.dart index bea76e58e2..802215cbf7 100644 --- a/packages/flutter/test/services/image_cache_resize_test.dart +++ b/packages/flutter/test/painting/image_cache_resize_test.dart @@ -2,13 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/services.dart'; +import 'package:flutter/painting.dart'; import 'package:test/test.dart'; +import '../rendering/rendering_tester.dart'; import 'mocks_for_image_cache.dart'; void main() { - test('Image cache resizing', () async { + new TestRenderingFlutterBinding(); // initializes the imageCache + +test('Image cache resizing', () async { imageCache.maximumSize = 2; diff --git a/packages/flutter/test/services/image_cache_test.dart b/packages/flutter/test/painting/image_cache_test.dart similarity index 95% rename from packages/flutter/test/services/image_cache_test.dart rename to packages/flutter/test/painting/image_cache_test.dart index 9e0617664e..82c6744c40 100644 --- a/packages/flutter/test/services/image_cache_test.dart +++ b/packages/flutter/test/painting/image_cache_test.dart @@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/services.dart'; +import 'package:flutter/painting.dart'; import 'package:test/test.dart'; +import '../rendering/rendering_tester.dart'; import 'mocks_for_image_cache.dart'; void main() { + new TestRenderingFlutterBinding(); // initializes the imageCache + test('Image cache', () async { imageCache.maximumSize = 3; diff --git a/packages/flutter/test/services/image_data.dart b/packages/flutter/test/painting/image_data.dart similarity index 100% rename from packages/flutter/test/services/image_data.dart rename to packages/flutter/test/painting/image_data.dart diff --git a/packages/flutter/test/services/image_decoder_test.dart b/packages/flutter/test/painting/image_decoder_test.dart similarity index 93% rename from packages/flutter/test/services/image_decoder_test.dart rename to packages/flutter/test/painting/image_decoder_test.dart index 28e388af63..e693723946 100644 --- a/packages/flutter/test/services/image_decoder_test.dart +++ b/packages/flutter/test/painting/image_decoder_test.dart @@ -5,7 +5,7 @@ import 'dart:typed_data'; import 'dart:ui' as ui; -import 'package:flutter/services.dart'; +import 'package:flutter/painting.dart'; import 'package:test/test.dart'; import 'image_data.dart'; diff --git a/packages/flutter/test/services/image_provider_test.dart b/packages/flutter/test/painting/image_provider_test.dart similarity index 92% rename from packages/flutter/test/services/image_provider_test.dart rename to packages/flutter/test/painting/image_provider_test.dart index 08512356a4..1513da093f 100644 --- a/packages/flutter/test/services/image_provider_test.dart +++ b/packages/flutter/test/painting/image_provider_test.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/services.dart'; +import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { diff --git a/packages/flutter/test/services/image_stream_test.dart b/packages/flutter/test/painting/image_stream_test.dart similarity index 99% rename from packages/flutter/test/services/image_stream_test.dart rename to packages/flutter/test/painting/image_stream_test.dart index 331d78b073..46bdd9afc1 100644 --- a/packages/flutter/test/services/image_stream_test.dart +++ b/packages/flutter/test/painting/image_stream_test.dart @@ -4,8 +4,9 @@ import 'dart:async'; import 'dart:ui'; + +import 'package:flutter/painting.dart'; import 'package:flutter/scheduler.dart' show timeDilation; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; class FakeFrameInfo extends FrameInfo { diff --git a/packages/flutter/test/services/image_test_utils.dart b/packages/flutter/test/painting/image_test_utils.dart similarity index 97% rename from packages/flutter/test/services/image_test_utils.dart rename to packages/flutter/test/painting/image_test_utils.dart index 170f266207..8a8b5311e0 100644 --- a/packages/flutter/test/services/image_test_utils.dart +++ b/packages/flutter/test/painting/image_test_utils.dart @@ -7,7 +7,7 @@ import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; +import 'package:flutter/painting.dart'; import 'image_data.dart'; diff --git a/packages/flutter/test/services/mocks_for_image_cache.dart b/packages/flutter/test/painting/mocks_for_image_cache.dart similarity index 97% rename from packages/flutter/test/services/mocks_for_image_cache.dart rename to packages/flutter/test/painting/mocks_for_image_cache.dart index 5623fdb739..b910a8e24a 100644 --- a/packages/flutter/test/services/mocks_for_image_cache.dart +++ b/packages/flutter/test/painting/mocks_for_image_cache.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; +import 'package:flutter/painting.dart'; class TestImageInfo implements ImageInfo { const TestImageInfo(this.value, { this.image, this.scale }); diff --git a/packages/flutter/test/painting/shape_decoration_test.dart b/packages/flutter/test/painting/shape_decoration_test.dart index ba8613d39b..bcc8ae5933 100644 --- a/packages/flutter/test/painting/shape_decoration_test.dart +++ b/packages/flutter/test/painting/shape_decoration_test.dart @@ -6,12 +6,14 @@ import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; +import '../rendering/rendering_tester.dart'; void main() { + new TestRenderingFlutterBinding(); // initializes the imageCache + test('ShapeDecoration constructor', () { final Color colorR = const Color(0xffff0000); final Color colorG = const Color(0xff00ff00); diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart index 8f778c22d5..bbd79d49b0 100644 --- a/packages/flutter/test/rendering/rendering_tester.dart +++ b/packages/flutter/test/rendering/rendering_tester.dart @@ -11,7 +11,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart' show EnginePhase; export 'package:flutter_test/flutter_test.dart' show EnginePhase; -class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, RendererBinding, GestureBinding { +class TestRenderingFlutterBinding extends BindingBase with ServicesBinding, GestureBinding, SchedulerBinding, PaintingBinding, RendererBinding { EnginePhase phase = EnginePhase.composite; @override diff --git a/packages/flutter/test/services/asset_bundle_test.dart b/packages/flutter/test/services/asset_bundle_test.dart index 8ca6313f76..9be659004e 100644 --- a/packages/flutter/test/services/asset_bundle_test.dart +++ b/packages/flutter/test/services/asset_bundle_test.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; +import 'package:flutter/painting.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/flutter/test/widgets/fade_in_image_test.dart b/packages/flutter/test/widgets/fade_in_image_test.dart index 61bf99a8e2..63cfa8dcec 100644 --- a/packages/flutter/test/widgets/fade_in_image_test.dart +++ b/packages/flutter/test/widgets/fade_in_image_test.dart @@ -7,7 +7,7 @@ import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../services/image_test_utils.dart'; +import '../painting/image_test_utils.dart'; Future main() async { // These must run outside test zone to complete diff --git a/packages/flutter/test/widgets/image_headers_test.dart b/packages/flutter/test/widgets/image_headers_test.dart index b10f69cbb0..c6f62954aa 100644 --- a/packages/flutter/test/widgets/image_headers_test.dart +++ b/packages/flutter/test/widgets/image_headers_test.dart @@ -10,7 +10,7 @@ import 'package:http/http.dart' as http; import 'package:http/testing.dart' as http; import 'package:flutter/services.dart' show createHttpClient; -import '../services/image_data.dart'; +import '../painting/image_data.dart'; void main() { testWidgets('Headers', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/image_icon_test.dart b/packages/flutter/test/widgets/image_icon_test.dart index 8212083ac0..c581716cdc 100644 --- a/packages/flutter/test/widgets/image_icon_test.dart +++ b/packages/flutter/test/widgets/image_icon_test.dart @@ -3,11 +3,10 @@ // found in the LICENSE file. import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../services/mocks_for_image_cache.dart'; +import '../painting/mocks_for_image_cache.dart'; const ImageProvider _kImage = const TestImageProvider(21, 42); diff --git a/packages/flutter/test/widgets/image_package_asset_test.dart b/packages/flutter/test/widgets/image_package_asset_test.dart index e27ba92cba..15f26102ce 100644 --- a/packages/flutter/test/widgets/image_package_asset_test.dart +++ b/packages/flutter/test/widgets/image_package_asset_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart index 6403a7ab0d..522616bda1 100644 --- a/packages/flutter/test/widgets/image_rtl_test.dart +++ b/packages/flutter/test/widgets/image_rtl_test.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index af4216d8de..05ae19d902 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -8,11 +8,10 @@ import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../services/image_data.dart'; +import '../painting/image_data.dart'; void main() { testWidgets('Verify Image resets its RenderImage when changing providers', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/obscured_animated_image.dart b/packages/flutter/test/widgets/obscured_animated_image.dart index 1a449314aa..41ff442f56 100644 --- a/packages/flutter/test/widgets/obscured_animated_image.dart +++ b/packages/flutter/test/widgets/obscured_animated_image.dart @@ -9,9 +9,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../services/fake_codec.dart'; -import '../services/fake_image_provider.dart'; -import '../services/image_data.dart'; +import '../painting/fake_codec.dart'; +import '../painting/fake_image_provider.dart'; +import '../painting/image_data.dart'; Future main() async { final FakeCodec fakeCodec = await FakeCodec.fromData(new Uint8List.fromList(kAnimatedGif)); diff --git a/packages/flutter_driver/lib/src/extension/extension.dart b/packages/flutter_driver/lib/src/extension/extension.dart index 05cee0c012..95ab580aba 100644 --- a/packages/flutter_driver/lib/src/extension/extension.dart +++ b/packages/flutter_driver/lib/src/extension/extension.dart @@ -35,7 +35,7 @@ const String _extensionMethod = 'ext.flutter.$_extensionMethodName'; /// eventually completes to a string response. typedef Future DataHandler(String message); -class _DriverBinding extends BindingBase with SchedulerBinding, GestureBinding, ServicesBinding, RendererBinding, WidgetsBinding { +class _DriverBinding extends BindingBase with ServicesBinding, SchedulerBinding, GestureBinding, PaintingBinding, RendererBinding, WidgetsBinding { _DriverBinding(this._handler); final DataHandler _handler; diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index 376a50859c..f70cf1a3fa 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -86,7 +86,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase with SchedulerBinding, GestureBinding, RendererBinding, - // Services binding omitted to avoid dragging in the licenses code. + ServicesBinding, + PaintingBinding, WidgetsBinding { /// Constructor for [TestWidgetsFlutterBinding]. @@ -150,6 +151,12 @@ abstract class TestWidgetsFlutterBinding extends BindingBase super.initInstances(); } + @override + void initLicenses() { + // Do not include any licenses, because we're a test, and the LICENSE file + // doesn't get generated for tests. + } + /// Whether there is currently a test executing. bool get inTest;