Switch to the assets plugin (#6408)
This patch removes our dependency on asset_bundle.mojom.
diff --git a/examples/flutter_gallery/test/example_code_parser_test.dart b/examples/flutter_gallery/test/example_code_parser_test.dart
index c93e82d..68ffad6 100644
--- a/examples/flutter_gallery/test/example_code_parser_test.dart
+++ b/examples/flutter_gallery/test/example_code_parser_test.dart
@@ -3,10 +3,10 @@
// found in the LICENSE file.
import 'dart:async';
+import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter_gallery/gallery/example_code_parser.dart';
-import 'package:mojo/core.dart' as core;
import 'package:test/test.dart';
void main() {
@@ -36,7 +36,7 @@
class TestAssetBundle extends AssetBundle {
@override
- Future<core.MojoDataPipeConsumer> load(String key) => null;
+ Future<ByteData> load(String key) => null;
@override
Future<String> loadString(String key, { bool cache: true }) {
diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart
index 00bb656..2ab59b9 100644
--- a/packages/flutter/lib/src/services/asset_bundle.dart
+++ b/packages/flutter/lib/src/services/asset_bundle.dart
@@ -4,14 +4,12 @@
import 'dart:async';
import 'dart:convert';
-import 'dart:io';
-import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/http.dart' as http;
-import 'package:mojo/core.dart' as core;
-import 'package:flutter_services/mojo/asset_bundle/asset_bundle.dart' as mojom;
+
+import 'platform_messages.dart';
/// A collection of resources used by the application.
///
@@ -42,7 +40,7 @@
/// * [rootBundle]
abstract class AssetBundle {
/// Retrieve a binary resource from the asset bundle as a data stream.
- Future<core.MojoDataPipeConsumer> load(String key);
+ Future<ByteData> load(String key);
/// Retrieve a string from the asset bundle.
///
@@ -83,13 +81,11 @@
String _urlFromKey(String key) => _baseUrl.resolve(key).toString();
@override
- Future<core.MojoDataPipeConsumer> load(String key) async {
+ Future<ByteData> load(String key) async {
http.Response response = await http.get(_urlFromKey(key));
if (response.statusCode == 200)
return null;
- core.MojoDataPipe pipe = new core.MojoDataPipe();
- core.DataPipeFiller.fillHandle(pipe.producer, response.bodyBytes.buffer.asByteData());
- return pipe.consumer;
+ return response.bodyBytes.buffer.asByteData();
}
@override
@@ -138,9 +134,8 @@
}
Future<String> _fetchString(String key) async {
- final core.MojoDataPipeConsumer pipe = await load(key);
- final ByteData data = await core.DataPipeDrainer.drainHandle(pipe);
- return UTF8.decode(new Uint8List.view(data.buffer));
+ final ByteData data = await load(key);
+ return UTF8.decode(data.buffer.asUint8List());
}
/// Retrieve a string from the asset bundle, parse it with the given function,
@@ -190,47 +185,17 @@
}
}
-/// An [AssetBundle] that loads resources from a Mojo service.
-class MojoAssetBundle extends CachingAssetBundle {
- /// Creates an [AssetBundle] interface around the given [mojom.AssetBundleProxy] Mojo service.
- MojoAssetBundle(this._bundle);
-
- mojom.AssetBundleProxy _bundle;
-
+/// An [AssetBundle] that loads resources using platform messages.
+class PlatformAssetBundle extends CachingAssetBundle {
@override
- Future<core.MojoDataPipeConsumer> load(String key) {
- Completer<core.MojoDataPipeConsumer> completer = new Completer<core.MojoDataPipeConsumer>();
- _bundle.getAsStream(key, (core.MojoDataPipeConsumer assetData) {
- completer.complete(assetData);
- });
- return completer.future;
+ Future<ByteData> load(String key) {
+ Uint8List encoded = UTF8.encoder.convert(key);
+ return PlatformMessages.sendBinary('flutter/assets', encoded.buffer.asByteData());
}
}
AssetBundle _initRootBundle() {
- int h = ui.MojoServices.takeRootBundle();
- if (h == core.MojoHandle.INVALID) {
- assert(() {
- if (!Platform.environment.containsKey('FLUTTER_TEST')) {
- FlutterError.reportError(new FlutterErrorDetails(
- exception:
- 'dart:ui MojoServices.takeRootBundle() returned an invalid handle.\n'
- 'This might happen if the Dart VM was restarted without restarting the underlying Flutter engine, '
- 'or if the Flutter framework\'s rootBundle object was first accessed after some other code called '
- 'takeRootBundle. The root bundle handle can only be obtained once in the lifetime of the Flutter '
- 'engine. Mojo handles cannot be shared.\n'
- 'The rootBundle object will be initialised with a NetworkAssetBundle instead of a MojoAssetBundle. '
- 'This may cause subsequent network errors.',
- library: 'services library',
- context: 'while initialising the root bundle'
- ));
- }
- return true;
- });
- return new NetworkAssetBundle(Uri.base);
- }
- core.MojoHandle handle = new core.MojoHandle(h);
- return new MojoAssetBundle(new mojom.AssetBundleProxy.fromHandle(handle));
+ return new PlatformAssetBundle();
}
/// The [AssetBundle] from which this application was loaded.
@@ -248,10 +213,6 @@
/// convenience, the [WidgetsApp] or [MaterialApp] widget at the top of the
/// widget hierarchy configures the [DefaultAssetBundle] to be the [rootBundle].
///
-/// In normal operation, the [rootBundle] is a [MojoAssetBundle], though it can
-/// also end up being a [NetworkAssetBundle] in some cases (e.g. if the
-/// application's resources are being served from a local HTTP server).
-///
/// See also:
///
/// * [DefaultAssetBundle]
diff --git a/packages/flutter/lib/src/services/image_provider.dart b/packages/flutter/lib/src/services/image_provider.dart
index 5d6e36c..7fec73f 100644
--- a/packages/flutter/lib/src/services/image_provider.dart
+++ b/packages/flutter/lib/src/services/image_provider.dart
@@ -10,7 +10,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/http.dart' as http;
import 'package:meta/meta.dart';
-import 'package:mojo/core.dart' as mojo;
import 'asset_bundle.dart';
import 'image_cache.dart';
@@ -209,26 +208,62 @@
String toString() => '$runtimeType()';
}
-/// A subclass of [ImageProvider] that knows how to invoke
-/// [decodeImageFromDataPipe].
+/// Key for the image obtained by an [AssetImage] or [ExactAssetImage].
///
-/// This factors out the common logic of many [ImageProvider] classes,
-/// simplifying what subclasses must implement to just three small methods:
+/// This is used to identify the precise resource in the [imageCache].
+class AssetBundleImageKey {
+ /// Creates the key for an [AssetImage] or [AssetBundleImageProvider].
+ ///
+ /// The arguments must not be null.
+ const AssetBundleImageKey({
+ @required this.bundle,
+ @required this.name,
+ @required this.scale
+ });
+
+ /// The bundle from which the image will be obtained.
+ ///
+ /// The image is obtained by calling [AssetBundle.load] on the given [bundle]
+ /// using the key given by [name].
+ final AssetBundle bundle;
+
+ /// The key to use to obtain the resource from the [bundle]. This is the
+ /// argument passed to [AssetBundle.load].
+ final String name;
+
+ /// The scale to place in the [ImageInfo] object of the image.
+ final double scale;
+
+ @override
+ bool operator ==(dynamic other) {
+ if (other.runtimeType != runtimeType)
+ return false;
+ final AssetBundleImageKey typedOther = other;
+ return bundle == typedOther.bundle
+ && name == typedOther.name
+ && scale == typedOther.scale;
+ }
+
+ @override
+ int get hashCode => hashValues(bundle, name, scale);
+
+ @override
+ String toString() => '$runtimeType(bundle: $bundle, name: $name, scale: $scale)';
+}
+
+/// A subclass of [ImageProvider] that knows about [AssetBundle]s.
///
-/// * [obtainKey], to resolve an [ImageConfiguration].
-/// * [getScale], to determine the scale of the image associated with a
-/// particular key.
-/// * [loadDataPipe], to obtain the [mojo.MojoDataPipeConsumer] object that
-/// contains the actual image data.
-abstract class DataPipeImageProvider<T> extends ImageProvider<T> {
+/// This factors out the common logic of [AssetBundle]-based [ImageProvider]
+/// classes, simplifying what subclasses must implement to just [obtainKey].
+abstract class AssetBundleImageProvider extends ImageProvider<AssetBundleImageKey> {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
- const DataPipeImageProvider();
+ const AssetBundleImageProvider();
/// Converts a key into an [ImageStreamCompleter], and begins fetching the
/// image using [loadAsync].
@override
- ImageStreamCompleter load(T key) {
+ ImageStreamCompleter load(AssetBundleImageKey key) {
return new OneFrameImageStreamCompleter(
loadAsync(key),
informationCollector: (StringBuffer information) {
@@ -238,39 +273,29 @@
);
}
- /// Fetches the image from the data pipe, decodes it, and returns a
+ /// Fetches the image from the asset bundle, decodes it, and returns a
/// corresponding [ImageInfo] object.
///
/// This function is used by [load].
@protected
- Future<ImageInfo> loadAsync(T key) async {
- final mojo.MojoDataPipeConsumer dataPipe = await loadDataPipe(key);
- if (dataPipe == null)
+ Future<ImageInfo> loadAsync(AssetBundleImageKey key) async {
+ final ByteData data = await key.bundle.load(key.name);
+ if (data == null)
throw 'Unable to read data';
- final ui.Image image = await decodeImage(dataPipe);
+ final ui.Image image = await decodeImage(data);
if (image == null)
throw 'Unable to decode image data';
- return new ImageInfo(image: image, scale: getScale(key));
+ return new ImageInfo(image: image, scale: key.scale);
}
- /// Converts raw image data from a [mojo.MojoDataPipeConsumer] data pipe into
- /// a decoded [ui.Image] which can be passed to a [Canvas].
+ /// Converts raw image data from a [ByteData] buffer into a decoded
+ /// [ui.Image] which can be passed to a [Canvas].
///
- /// By default, this just uses [decodeImageFromDataPipe]. This method could be
+ /// By default, this just uses [decodeImageFromList]. This method could be
/// overridden in subclasses (e.g. for testing).
- Future<ui.Image> decodeImage(mojo.MojoDataPipeConsumer pipe) => decodeImageFromDataPipe(pipe);
-
- /// Returns the data pipe that contains the image data to decode.
- ///
- /// Must be implemented by subclasses of [DataPipeImageProvider].
- @protected
- Future<mojo.MojoDataPipeConsumer> loadDataPipe(T key);
-
- /// Returns the scale to use when creating the [ImageInfo] for the given key.
- ///
- /// Must be implemented by subclasses of [DataPipeImageProvider].
- @protected
- double getScale(T key);
+ Future<ui.Image> decodeImage(ByteData data) {
+ return decodeImageFromList(data.buffer.asUint8List());
+ }
}
/// Fetches the given URL from the network, associating it with the given scale.
@@ -345,72 +370,6 @@
String toString() => '$runtimeType("$url", scale: $scale)';
}
-/// Key for the image obtained by an [AssetImage] or [AssetBundleImageProvider].
-///
-/// This is used to identify the precise resource in the [imageCache].
-class AssetBundleImageKey {
- /// Creates the key for an [AssetImage] or [AssetBundleImageProvider].
- ///
- /// The arguments must not be null.
- const AssetBundleImageKey({
- @required this.bundle,
- @required this.name,
- @required this.scale
- });
-
- /// The bundle from which the image will be obtained.
- ///
- /// The image is obtained by calling [AssetBundle.load] on the given [bundle]
- /// using the key given by [name].
- final AssetBundle bundle;
-
- /// The key to use to obtain the resource from the [bundle]. This is the
- /// argument passed to [AssetBundle.load].
- final String name;
-
- /// The scale to place in the [ImageInfo] object of the image.
- final double scale;
-
- @override
- bool operator ==(dynamic other) {
- if (other.runtimeType != runtimeType)
- return false;
- final AssetBundleImageKey typedOther = other;
- return bundle == typedOther.bundle
- && name == typedOther.name
- && scale == typedOther.scale;
- }
-
- @override
- int get hashCode => hashValues(bundle, name, scale);
-
- @override
- String toString() => '$runtimeType(bundle: $bundle, name: $name, scale: $scale)';
-}
-
-/// A subclass of [DataPipeImageProvider] that knows about [AssetBundle]s.
-///
-/// This factors out the common logic of [AssetBundle]-based [ImageProvider]
-/// classes, simplifying what subclasses must implement to just [obtainKey].
-abstract class AssetBundleImageProvider extends DataPipeImageProvider<AssetBundleImageKey> {
- /// Abstract const constructor. This constructor enables subclasses to provide
- /// const constructors so that they can be used in const expressions.
- const AssetBundleImageProvider();
-
- @override
- Future<AssetBundleImageKey> obtainKey(ImageConfiguration configuration);
-
- @override
- Future<mojo.MojoDataPipeConsumer> loadDataPipe(AssetBundleImageKey key) {
- return key.bundle.load(key.name);
- }
-
- @override
- double getScale(AssetBundleImageKey key) {
- return key.scale;
- }
-}
-
/// Fetches an image from an [AssetBundle], associating it with the given scale.
///
/// This implementation requires an explicit final [name] and [scale] on
diff --git a/packages/flutter/test/widget/image_resolution_test.dart b/packages/flutter/test/widget/image_resolution_test.dart
index 3986e8c..37819d4 100644
--- a/packages/flutter/test/widget/image_resolution_test.dart
+++ b/packages/flutter/test/widget/image_resolution_test.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
+import 'dart:typed_data';
import 'dart:ui' as ui show Image;
import 'package:flutter/rendering.dart';
@@ -10,7 +11,6 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:meta/meta.dart';
-import 'package:mojo/core.dart' as mojo;
class TestImage extends ui.Image {
TestImage(this.scale);
@@ -26,9 +26,12 @@
void dispose() { }
}
-class TestMojoDataPipeConsumer extends mojo.MojoDataPipeConsumer {
- TestMojoDataPipeConsumer(this.scale) : super(null);
+class TestByteData implements ByteData {
+ TestByteData(this.scale);
final double scale;
+
+ @override
+ dynamic noSuchMethod(Invocation invocation) => null;
}
String testManifest = '''
@@ -44,26 +47,26 @@
class TestAssetBundle extends CachingAssetBundle {
@override
- Future<mojo.MojoDataPipeConsumer> load(String key) {
- mojo.MojoDataPipeConsumer pipe;
+ Future<ByteData> load(String key) {
+ ByteData data;
switch (key) {
case 'assets/image.png':
- pipe = new TestMojoDataPipeConsumer(1.0);
+ data = new TestByteData(1.0);
break;
case 'assets/1.5x/image.png':
- pipe = new TestMojoDataPipeConsumer(1.5);
+ data = new TestByteData(1.5);
break;
case 'assets/2.0x/image.png':
- pipe = new TestMojoDataPipeConsumer(2.0);
+ data = new TestByteData(2.0);
break;
case 'assets/3.0x/image.png':
- pipe = new TestMojoDataPipeConsumer(3.0);
+ data = new TestByteData(3.0);
break;
case 'assets/4.0x/image.png':
- pipe = new TestMojoDataPipeConsumer(4.0);
+ data = new TestByteData(4.0);
break;
}
- return new SynchronousFuture<mojo.MojoDataPipeConsumer>(pipe);
+ return new SynchronousFuture<ByteData>(data);
}
@override
@@ -83,9 +86,9 @@
@override
Future<ImageInfo> loadAsync(AssetBundleImageKey key) {
ImageInfo result;
- key.bundle.load(key.name).then((mojo.MojoDataPipeConsumer dataPipe) {
- decodeImage(dataPipe).then((ui.Image image) {
- result = new ImageInfo(image: image, scale: getScale(key));
+ key.bundle.load(key.name).then((ByteData data) {
+ decodeImage(data).then((ui.Image image) {
+ result = new ImageInfo(image: image, scale: key.scale);
});
});
assert(result != null);
@@ -93,8 +96,8 @@
}
@override
- Future<ui.Image> decodeImage(@checked TestMojoDataPipeConsumer pipe) {
- return new SynchronousFuture<ui.Image>(new TestImage(pipe.scale));
+ Future<ui.Image> decodeImage(@checked TestByteData data) {
+ return new SynchronousFuture<ui.Image>(new TestImage(data.scale));
}
}