Update engine to include new version of Mojo (#4668)

This required switching from the Future-based bindings to the callback-based
bindings.
diff --git a/bin/cache/engine.version b/bin/cache/engine.version
index 7997fb3..994e449 100644
--- a/bin/cache/engine.version
+++ b/bin/cache/engine.version
@@ -1 +1 @@
-e0ae976409ccbf25e8e26d66c4575d081fc2abdf
+f91f5ad62f7a61de787e3e6397f0b63e9eab534e
diff --git a/examples/layers/services/media_service.dart b/examples/layers/services/media_service.dart
index ba4afbb..d76ebee 100644
--- a/examples/layers/services/media_service.dart
+++ b/examples/layers/services/media_service.dart
@@ -42,7 +42,7 @@
   Future<Null> load(mojom.MediaServiceProxy mediaService) async {
     try {
       mediaService.createPlayer(player);
-      await player.prepare(await http.readDataPipe(soundUrl));
+      player.prepare(await http.readDataPipe(soundUrl), (bool ignored) { });
     } catch (e) {
       print("Error: failed to load sound file $soundUrl");
       player.close();
diff --git a/packages/flutter/lib/src/http/mojo_client.dart b/packages/flutter/lib/src/http/mojo_client.dart
index 7d24526..3403786 100644
--- a/packages/flutter/lib/src/http/mojo_client.dart
+++ b/packages/flutter/lib/src/http/mojo_client.dart
@@ -130,28 +130,26 @@
   ///
   /// The Future will emit a [ClientException] if the response doesn't have a
   /// success status code.
-  Future<mojo.MojoDataPipeConsumer> readDataPipe(dynamic url, { Map<String, String> headers }) async {
+  Future<mojo.MojoDataPipeConsumer> readDataPipe(dynamic url, { Map<String, String> headers }) {
+    Completer<mojo.MojoDataPipeConsumer> completer = new Completer<mojo.MojoDataPipeConsumer>();
     mojom.UrlLoaderProxy loader = new mojom.UrlLoaderProxy.unbound();
-    mojom.UrlRequest request = _prepareRequest('GET', url, headers);
-    mojom.UrlResponse response;
-    try {
-      networkService.createUrlLoader(loader);
-      response = (await loader.start(request)).response;
-    } catch (exception, stack) {
-      FlutterError.reportError(new FlutterErrorDetails(
-        exception: exception,
-        stack: stack,
-        library: 'networking HTTP library',
-        context: 'while sending bytes to the Mojo network library',
-        silent: true
-      ));
-      return null;
-    } finally {
+    networkService.createUrlLoader(loader);
+    loader.start(_prepareRequest('GET', url, headers), (mojom.UrlResponse response) {
       loader.close();
-    }
-    if (response.statusCode < 400)
-      return response.body;
-    throw new Exception("Request to $url failed with status ${response.statusCode}.");
+      if (response.statusCode < 400) {
+        completer.complete(response.body);
+      } else {
+        Exception exception = new Exception("Request to $url failed with status ${response.statusCode}.");
+        FlutterError.reportError(new FlutterErrorDetails(
+          exception: exception,
+          library: 'networking HTTP library',
+          context: 'while sending bytes to the Mojo network library',
+          silent: true
+        ));
+        completer.completeError(exception);
+      }
+    });
+    return completer.future;
   }
 
   mojom.UrlRequest _prepareRequest(String method, dynamic url, Map<String, String> headers, [dynamic body, Encoding encoding = UTF8]) {
@@ -177,35 +175,37 @@
     return request;
   }
 
-  Future<Response> _send(String method, dynamic url, Map<String, String> headers, [dynamic body, Encoding encoding = UTF8]) async {
+  Future<Response> _send(String method, dynamic url, Map<String, String> headers, [dynamic body, Encoding encoding = UTF8]) {
+    Completer<Response> completer = new Completer<Response>();
     mojom.UrlLoaderProxy loader = new mojom.UrlLoaderProxy.unbound();
+    networkService.createUrlLoader(loader);
     mojom.UrlRequest request = _prepareRequest(method, url, headers, body, encoding);
-    try {
-      networkService.createUrlLoader(loader);
-      mojom.UrlResponse response = (await loader.start(request)).response;
-      ByteData data = await mojo.DataPipeDrainer.drainHandle(response.body);
-      Uint8List bodyBytes = new Uint8List.view(data.buffer);
-      Map<String, String> headers = <String, String>{};
-      if (response.headers != null) {
-        for (mojom.HttpHeader header in response.headers) {
-          String headerName = header.name.toLowerCase();
-          String existingValue = headers[headerName];
-          headers[headerName] = existingValue != null ? '$existingValue, ${header.value}' : header.value;
-        }
-      }
-      return new Response.bytes(bodyBytes, response.statusCode, headers: headers);
-    } catch (exception, stack) {
-      FlutterError.reportError(new FlutterErrorDetails(
-        exception: exception,
-        stack: stack,
-        library: 'networking HTTP library',
-        context: 'while sending bytes to the Mojo network library',
-        silent: true
-      ));
-      return new Response.bytes(null, 500);
-    } finally {
+    loader.start(request, (mojom.UrlResponse response) async {
       loader.close();
-    }
+      try {
+        ByteData data = await mojo.DataPipeDrainer.drainHandle(response.body);
+        Uint8List bodyBytes = new Uint8List.view(data.buffer);
+        Map<String, String> headers = <String, String>{};
+        if (response.headers != null) {
+          for (mojom.HttpHeader header in response.headers) {
+            String headerName = header.name.toLowerCase();
+            String existingValue = headers[headerName];
+            headers[headerName] = existingValue != null ? '$existingValue, ${header.value}' : header.value;
+          }
+        }
+        completer.complete(new Response.bytes(bodyBytes, response.statusCode, headers: headers));
+      } catch (exception, stack) {
+        FlutterError.reportError(new FlutterErrorDetails(
+          exception: exception,
+          stack: stack,
+          library: 'networking HTTP library',
+          context: 'while sending bytes to the Mojo network library',
+          silent: true
+        ));
+        completer.complete(new Response.bytes(null, 500));
+      }
+    });
+    return completer.future;
   }
 
   void _checkResponseSuccess(dynamic url, Response response) {
diff --git a/packages/flutter/lib/src/rendering/child_view.dart b/packages/flutter/lib/src/rendering/child_view.dart
index 73d556b..be5b2a9 100644
--- a/packages/flutter/lib/src/rendering/child_view.dart
+++ b/packages/flutter/lib/src/rendering/child_view.dart
@@ -79,11 +79,10 @@
       url, mojom.ViewProvider.connectToService
     );
     mojom.ServiceProviderProxy incomingServices = new mojom.ServiceProviderProxy.unbound();
-    mojom.ServiceProviderStub outgoingServices = new mojom.ServiceProviderStub.unbound();
     _viewOwner = new mojom.ViewOwnerProxy.unbound();
-    viewProvider.createView(_viewOwner, incomingServices, outgoingServices);
+    viewProvider.createView(_viewOwner, incomingServices);
     viewProvider.close();
-    _connection = new ApplicationConnection(outgoingServices, incomingServices);
+    _connection = new ApplicationConnection(null, incomingServices);
   }
 
   /// Wraps an already-established connection to a child app.
diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart
index af0b2c7..e0b1716 100644
--- a/packages/flutter/lib/src/services/asset_bundle.dart
+++ b/packages/flutter/lib/src/services/asset_bundle.dart
@@ -180,8 +180,12 @@
   mojom.AssetBundleProxy _bundle;
 
   @override
-  Future<core.MojoDataPipeConsumer> load(String key) async {
-    return (await _bundle.getAsStream(key)).assetData;
+  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;
   }
 }
 
diff --git a/packages/flutter/lib/src/services/clipboard.dart b/packages/flutter/lib/src/services/clipboard.dart
index 5ae7f30..c7b6142 100644
--- a/packages/flutter/lib/src/services/clipboard.dart
+++ b/packages/flutter/lib/src/services/clipboard.dart
@@ -31,7 +31,11 @@
   /// Retrieves data from the clipboard that matches the given format.
   ///
   ///  * `format` is a media type, such as `text/plain`.
-  static Future<mojom.ClipboardData> getClipboardData(String format) async {
-    return (await _clipboardProxy.getClipboardData(format)).clip;
+  static Future<mojom.ClipboardData> getClipboardData(String format) {
+    Completer<mojom.ClipboardData> completer = new Completer<mojom.ClipboardData>();
+    _clipboardProxy.getClipboardData(format, (mojom.ClipboardData clip) {
+      completer.complete(clip);
+    });
+    return completer.future;
   }
 }
diff --git a/packages/flutter/lib/src/services/haptic_feedback.dart b/packages/flutter/lib/src/services/haptic_feedback.dart
index 4c94060..0d4f966 100644
--- a/packages/flutter/lib/src/services/haptic_feedback.dart
+++ b/packages/flutter/lib/src/services/haptic_feedback.dart
@@ -36,7 +36,11 @@
   ///   was successfully conveyed to the embedder. There may not be any actual
   ///   feedback if the device does not have a vibrator or one is disabled in
   ///   system settings.
-  static Future<bool> vibrate() async {
-    return (await _hapticFeedbackProxy.vibrate()).success;
+  static Future<bool> vibrate() {
+    Completer<bool> completer = new Completer<bool>();
+    _hapticFeedbackProxy.vibrate((bool result) {
+      completer.complete(result);
+    });
+    return completer.future;
   }
 }
diff --git a/packages/flutter/lib/src/services/host_messages.dart b/packages/flutter/lib/src/services/host_messages.dart
index ecba71c..6f0abe0 100644
--- a/packages/flutter/lib/src/services/host_messages.dart
+++ b/packages/flutter/lib/src/services/host_messages.dart
@@ -49,13 +49,21 @@
 /// Flutter framework to exchange application-specific messages.
 class HostMessages {
   /// Send a message to the host application.
-  static Future<String> sendToHost(String messageName, [String message = '']) async {
-    return (await _hostAppMessagesProxy.sendString(messageName, message)).reply;
+  static Future<String> sendToHost(String messageName, [String message = '']) {
+    Completer<String> completer = new Completer<String>();
+    _hostAppMessagesProxy.sendString(messageName, message, (String reply) {
+      completer.complete(reply);
+    });
+    return completer.future;
   }
 
   /// Sends a JSON-encoded message to the host application and JSON-decodes the response.
   static Future<dynamic> sendJSON(String messageName, [dynamic json]) async {
-    return JSON.decode((await _hostAppMessagesProxy.sendString(messageName, JSON.encode(json))).reply);
+    Completer<dynamic> completer = new Completer<dynamic>();
+    _hostAppMessagesProxy.sendString(messageName, JSON.encode(json), (String reply) {
+      completer.complete(JSON.decode(reply));
+    });
+    return completer.future;
   }
 
   /// Register a callback for receiving messages from the host application.
diff --git a/packages/flutter/lib/src/services/path_provider.dart b/packages/flutter/lib/src/services/path_provider.dart
index 571962a..97a1760 100644
--- a/packages/flutter/lib/src/services/path_provider.dart
+++ b/packages/flutter/lib/src/services/path_provider.dart
@@ -29,8 +29,12 @@
   ///
   ///  * _iOS_: `NSTemporaryDirectory()`
   ///  * _Android_: `getCacheDir()` on the context.
-  static Future<Directory> getTemporaryDirectory() async {
-    return new Directory((await _pathProviderProxy.temporaryDirectory()).path);
+  static Future<Directory> getTemporaryDirectory() {
+    Completer<Directory> completer = new Completer<Directory>();
+    _pathProviderProxy.temporaryDirectory((String path) {
+      completer.complete(new Directory(path));
+    });
+    return completer.future;
   }
 
   /// Path to a directory where the application may place files that are private
@@ -41,7 +45,11 @@
   ///
   ///  * _iOS_: `NSDocumentsDirectory`
   ///  * _Android_: The AppData directory.
-  static Future<Directory> getApplicationDocumentsDirectory() async {
-    return new Directory((await _pathProviderProxy.applicationDocumentsDirectory()).path);
+  static Future<Directory> getApplicationDocumentsDirectory() {
+    Completer<Directory> completer = new Completer<Directory>();
+    _pathProviderProxy.applicationDocumentsDirectory((String path) {
+      completer.complete(new Directory(path));
+    });
+    return completer.future;
   }
 }
diff --git a/packages/flutter/lib/src/services/shell.dart b/packages/flutter/lib/src/services/shell.dart
index 47f53d3..b92dccb 100644
--- a/packages/flutter/lib/src/services/shell.dart
+++ b/packages/flutter/lib/src/services/shell.dart
@@ -64,7 +64,7 @@
       return;
     }
     mojom.ServiceProviderProxy services = new mojom.ServiceProviderProxy.unbound();
-    instance._shell.connectToApplication(url, services, null);
+    instance._shell.connectToApplication(url, services);
     core.MojoMessagePipe pipe = new core.MojoMessagePipe();
     proxy.ctrl.bind(pipe.endpoints[0]);
     services.connectToService_(serviceName, pipe.endpoints[1]);
@@ -116,9 +116,8 @@
     if (_shell == null)
       return null;
     mojom.ServiceProviderProxy services = new mojom.ServiceProviderProxy.unbound();
-    mojom.ServiceProviderStub exposedServices = new mojom.ServiceProviderStub.unbound();
-    _shell.connectToApplication(url, services, exposedServices);
-    return new ApplicationConnection(exposedServices, services);
+    _shell.connectToApplication(url, services);
+    return new ApplicationConnection(null, services);
   }
 
   /// Interceptor for calls to [connectToService] and
diff --git a/packages/flutter/lib/src/services/system_chrome.dart b/packages/flutter/lib/src/services/system_chrome.dart
index 5da8a67..97e305c 100644
--- a/packages/flutter/lib/src/services/system_chrome.dart
+++ b/packages/flutter/lib/src/services/system_chrome.dart
@@ -33,8 +33,12 @@
   ///
   ///   boolean indicating if the orientation mask is valid and the changes
   ///   could be conveyed successfully to the embedder.
-  static Future<bool> setPreferredOrientations(int deviceOrientationMask) async {
-    return (await _systemChromeProxy.setPreferredOrientations(deviceOrientationMask)).success;
+  static Future<bool> setPreferredOrientations(int deviceOrientationMask) {
+    Completer<bool> completer = new Completer<bool>();
+    _systemChromeProxy.setPreferredOrientations(deviceOrientationMask, (bool success) {
+      completer.complete(success);
+    });
+    return completer.future;
   }
 
   /// Specifies the description of the current state of the application as it
@@ -53,32 +57,12 @@
   ///
   ///   If application-specified metadata is unsupported on the platform,
   ///   specifying it is a no-op and always return true.
-  static Future<bool> setApplicationSwitcherDescription(mojom.ApplicationSwitcherDescription description) async {
-    return (await _systemChromeProxy.setApplicationSwitcherDescription(
-      description)).success;
-  }
-
-  /// Specifies the set of overlays visible on the embedder when the
-  /// application is running. The embedder may choose to ignore unsupported
-  /// overlays
-  ///
-  /// Arguments:
-  ///
-  ///  * [overlaysMask]: A mask of [SystemUIOverlay] enum values that denotes
-  ///    the overlays to show.
-  ///
-  /// Return Value:
-  ///
-  ///   boolean indicating if the preference was conveyed successfully to the
-  ///   embedder.
-  ///
-  /// Platform Specific Notes:
-  ///
-  ///   If the overlay is unsupported on the platform, enabling or disabling
-  ///   that overlay is a no-op and always return true.
-  static Future<bool> setEnabledSystemUIOverlays(int overlaysMask) async {
-    return (await _systemChromeProxy.setEnabledSystemUiOverlays(
-      overlaysMask)).success;
+  static Future<bool> setApplicationSwitcherDescription(mojom.ApplicationSwitcherDescription description) {
+    Completer<bool> completer = new Completer<bool>();
+    _systemChromeProxy.setApplicationSwitcherDescription(description, (bool success) {
+      completer.complete(success);
+    });
+    return completer.future;
   }
 
   /// Specifies the style of the system overlays that are visible on the
@@ -106,7 +90,9 @@
     scheduleMicrotask(() {
       assert(_pendingStyle != null);
       if (_pendingStyle != _latestStyle) {
-        _systemChromeProxy.setSystemUiOverlayStyle(_pendingStyle);
+        _systemChromeProxy.setSystemUiOverlayStyle(_pendingStyle, (bool success) {
+          // Ignored.
+        });
         _latestStyle = _pendingStyle;
       }
       _pendingStyle = null;
diff --git a/packages/flutter/lib/src/services/system_sound.dart b/packages/flutter/lib/src/services/system_sound.dart
index 5fe8c57..f0ebcd1 100644
--- a/packages/flutter/lib/src/services/system_sound.dart
+++ b/packages/flutter/lib/src/services/system_sound.dart
@@ -30,7 +30,11 @@
   ///   boolean indicating if the intent to play the specified sound was
   ///   successfully conveyed to the embedder. No sound may actually play if the
   ///   device is muted or the sound was not available on the platform.
-  static Future<bool> play(SystemSoundType type) async {
-    return (await _systemChromeProxy.play(type)).success;
+  static Future<bool> play(SystemSoundType type) {
+    Completer<bool> completer = new Completer<bool>();
+    _systemChromeProxy.play(type, (bool success) {
+      completer.complete(success);
+    });
+    return completer.future;
   }
 }
diff --git a/packages/flutter/test/widget/input_test.dart b/packages/flutter/test/widget/input_test.dart
index 41cb50e..aadd46c 100644
--- a/packages/flutter/test/widget/input_test.dart
+++ b/packages/flutter/test/widget/input_test.dart
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:async';
+
 import 'package:flutter_test/flutter_test.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
@@ -38,8 +40,10 @@
   }
 
   @override
-  dynamic getClipboardData(String format,[Function responseFactory = null]) {
-    return new mojom.ClipboardGetClipboardDataResponseParams()..clip = _clip;
+  void getClipboardData(String format, void callback(mojom.ClipboardData clip)) {
+    scheduleMicrotask(() {
+      callback(_clip);
+    });
   }
 }
 
diff --git a/packages/flutter_sprites/lib/src/sound.dart b/packages/flutter_sprites/lib/src/sound.dart
index aca4df0..e769c15 100644
--- a/packages/flutter_sprites/lib/src/sound.dart
+++ b/packages/flutter_sprites/lib/src/sound.dart
@@ -98,12 +98,15 @@
   int _nextStreamId = 0;
 
   /// Loads a sound effect.
-  Future<SoundEffect> load(MojoDataPipeConsumer data) async {
-    SoundPoolLoadResponseParams result = await _soundPool.load(data);
-    if (result.success)
-      return new SoundEffect(result.soundId);
-
-    throw new Exception('Unable to load sound');
+  Future<SoundEffect> load(MojoDataPipeConsumer data) {
+    Completer<SoundEffect> completer = new Completer<SoundEffect>();
+    _soundPool.load(data, (bool success, int soundId) {
+      if (success)
+        completer.complete(new SoundEffect(soundId));
+      else
+        completer.completeError(new Exception('Unable to load sound'));
+    });
+    return completer.future;
   }
 
   /// Plays a sound effect.
@@ -112,21 +115,26 @@
     double rightVolume: 1.0,
     bool loop: false,
     double pitch: 1.0
-  }) async {
+  }) {
+    Completer<SoundEffectStream> completer = new Completer<SoundEffectStream>();
     int streamId = _nextStreamId++;
-    SoundPoolPlayResponseParams result = await _soundPool.play(
-      sound._soundId, streamId, <double>[leftVolume, rightVolume], loop, pitch
-    );
-
-    if (result.success) {
-      return new SoundEffectStream(this, streamId,
-        leftVolume: leftVolume,
-        rightVolume: rightVolume,
-        pitch: pitch
-      );
-    }
-
-    throw new Exception('Unable to play sound');
+    _soundPool.play(sound._soundId,
+                    streamId,
+                    <double>[leftVolume, rightVolume],
+                    loop,
+                    pitch,
+                    (bool success) {
+      if (success) {
+        completer.complete(new SoundEffectStream(this, streamId,
+          leftVolume: leftVolume,
+          rightVolume: rightVolume,
+          pitch: pitch
+        ));
+      } else {
+        completer.completeError(new Exception('Unable to play sound'));
+      }
+    });
+    return completer.future;
   }
 
   /// Set to true to pause a sound effect.
@@ -203,8 +211,11 @@
     soundTrack._player = new MediaPlayerProxy.unbound();
     _mediaService.createPlayer(soundTrack._player);
 
-    await soundTrack._player.prepare(await pipe);
-    return soundTrack;
+    Completer<SoundTrack> completer = new Completer<SoundTrack>();
+    soundTrack._player.prepare(await pipe, (bool ignored) {
+      completer.complete(soundTrack);
+    });
+    return await completer.future;
   }
 
   /// Unloads a [SoundTrack] from memory.