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));
   }
 }