Commit d1cb026a authored by Adam Barth's avatar Adam Barth

Update engine and Mojo usage (#4258)

The new mojom.dart code makes mocking services a bit tricky. I've filed
https://github.com/domokit/mojo/issues/786 about improving that.
parent 49affc40
cc2cc42f2d3a56c9176f5a2de02b8993a046f88d b6ad88501f8f712c4181811c05d37afcf8d52168
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'package:sky_services/media/media.mojom.dart'; import 'package:sky_services/media/media.mojom.dart' as mojom;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
...@@ -24,25 +24,25 @@ class PianoKey { ...@@ -24,25 +24,25 @@ class PianoKey {
final Color color; final Color color;
final String soundUrl; final String soundUrl;
final MediaPlayerProxy player = new MediaPlayerProxy.unbound(); final mojom.MediaPlayerProxy player = new mojom.MediaPlayerProxy.unbound();
bool get isPlayerOpen => player.impl.isOpen; bool get isPlayerOpen => player.ctrl.isOpen;
void down() { void down() {
if (!isPlayerOpen) return; if (!isPlayerOpen) return;
player.ptr.seekTo(0); player.seekTo(0);
player.ptr.start(); player.start();
} }
void up() { void up() {
if (!isPlayerOpen) return; if (!isPlayerOpen) return;
player.ptr.pause(); player.pause();
} }
Future<Null> load(MediaServiceProxy mediaService) async { Future<Null> load(mojom.MediaServiceProxy mediaService) async {
try { try {
mediaService.ptr.createPlayer(player); mediaService.createPlayer(player);
await player.ptr.prepare(await http.readDataPipe(soundUrl)); await player.prepare(await http.readDataPipe(soundUrl));
} catch (e) { } catch (e) {
print("Error: failed to load sound file $soundUrl"); print("Error: failed to load sound file $soundUrl");
player.close(); player.close();
...@@ -61,9 +61,10 @@ class PianoApp extends StatelessWidget { ...@@ -61,9 +61,10 @@ class PianoApp extends StatelessWidget {
]; ];
Future<Null> loadSounds() async { Future<Null> loadSounds() async {
MediaServiceProxy mediaService = new MediaServiceProxy.unbound(); mojom.MediaServiceProxy mediaService = shell.connectToApplicationService(
'mojo:media_service', mojom.MediaService.connectToService
);
try { try {
shell.connectToService("mojo:media_service", mediaService);
List<Future<Null>> pending = <Future<Null>>[]; List<Future<Null>> pending = <Future<Null>>[];
for (PianoKey key in keys) for (PianoKey key in keys)
pending.add(key.load(mediaService)); pending.add(key.load(mediaService));
......
...@@ -135,8 +135,8 @@ class MojoClient { ...@@ -135,8 +135,8 @@ class MojoClient {
mojom.UrlRequest request = _prepareRequest('GET', url, headers); mojom.UrlRequest request = _prepareRequest('GET', url, headers);
mojom.UrlResponse response; mojom.UrlResponse response;
try { try {
networkService.ptr.createUrlLoader(loader); networkService.createUrlLoader(loader);
response = (await loader.ptr.start(request)).response; response = (await loader.start(request)).response;
} catch (exception, stack) { } catch (exception, stack) {
FlutterError.reportError(new FlutterErrorDetails( FlutterError.reportError(new FlutterErrorDetails(
exception: exception, exception: exception,
...@@ -181,8 +181,8 @@ class MojoClient { ...@@ -181,8 +181,8 @@ class MojoClient {
mojom.UrlLoaderProxy loader = new mojom.UrlLoaderProxy.unbound(); mojom.UrlLoaderProxy loader = new mojom.UrlLoaderProxy.unbound();
mojom.UrlRequest request = _prepareRequest(method, url, headers, body, encoding); mojom.UrlRequest request = _prepareRequest(method, url, headers, body, encoding);
try { try {
networkService.ptr.createUrlLoader(loader); networkService.createUrlLoader(loader);
mojom.UrlResponse response = (await loader.ptr.start(request)).response; mojom.UrlResponse response = (await loader.start(request)).response;
ByteData data = await mojo.DataPipeDrainer.drainHandle(response.body); ByteData data = await mojo.DataPipeDrainer.drainHandle(response.body);
Uint8List bodyBytes = new Uint8List.view(data.buffer); Uint8List bodyBytes = new Uint8List.view(data.buffer);
Map<String, String> headers = <String, String>{}; Map<String, String> headers = <String, String>{};
...@@ -215,9 +215,7 @@ class MojoClient { ...@@ -215,9 +215,7 @@ class MojoClient {
} }
static mojom.NetworkServiceProxy _initNetworkService() { static mojom.NetworkServiceProxy _initNetworkService() {
mojom.NetworkServiceProxy proxy = new mojom.NetworkServiceProxy.unbound(); return shell.connectToApplicationService('mojo:authenticated_network_service', mojom.NetworkService.connectToService);
shell.connectToService("mojo:authenticated_network_service", proxy);
return proxy;
} }
/// A handle to the [NetworkService] object used by [MojoClient]. /// A handle to the [NetworkService] object used by [MojoClient].
......
...@@ -34,15 +34,15 @@ mojom.ViewProxy _initViewProxy() { ...@@ -34,15 +34,15 @@ mojom.ViewProxy _initViewProxy() {
// view keys, which means any scheme for sharing the view host also needs to // view keys, which means any scheme for sharing the view host also needs to
// provide a mechanism for coordinating about view keys. // provide a mechanism for coordinating about view keys.
final mojom.ViewProxy _viewProxy = _initViewProxy(); final mojom.ViewProxy _viewProxy = _initViewProxy();
final mojom.View _view = _viewProxy?.ptr; final mojom.View _view = _viewProxy;
mojom.ViewContainer _initViewContainer() { mojom.ViewContainer _initViewContainer() {
if (_view == null) if (_view == null)
return null; return null;
mojom.ViewContainerProxy viewContainerProxy = new mojom.ViewContainerProxy.unbound(); mojom.ViewContainerProxy viewContainerProxy = new mojom.ViewContainerProxy.unbound();
_view.getContainer(viewContainerProxy); _view.getContainer(viewContainerProxy);
viewContainerProxy.ptr.setListener(new mojom.ViewContainerListenerStub.unbound()..impl = _ViewContainerListenerImpl.instance); viewContainerProxy.setListener(new mojom.ViewContainerListenerStub.unbound()..impl = _ViewContainerListenerImpl.instance);
return viewContainerProxy.ptr; return viewContainerProxy;
} }
final mojom.ViewContainer _viewContainer = _initViewContainer(); final mojom.ViewContainer _viewContainer = _initViewContainer();
...@@ -75,12 +75,13 @@ class _ViewContainerListenerImpl extends mojom.ViewContainerListener { ...@@ -75,12 +75,13 @@ class _ViewContainerListenerImpl extends mojom.ViewContainerListener {
class ChildViewConnection { class ChildViewConnection {
/// Establishes a connection to the app at the given URL. /// Establishes a connection to the app at the given URL.
ChildViewConnection({ String url }) { ChildViewConnection({ String url }) {
mojom.ViewProviderProxy viewProvider = new mojom.ViewProviderProxy.unbound(); mojom.ViewProviderProxy viewProvider = shell.connectToApplicationService(
shell.connectToService(url, viewProvider); url, mojom.ViewProvider.connectToService
);
mojom.ServiceProviderProxy incomingServices = new mojom.ServiceProviderProxy.unbound(); mojom.ServiceProviderProxy incomingServices = new mojom.ServiceProviderProxy.unbound();
mojom.ServiceProviderStub outgoingServices = new mojom.ServiceProviderStub.unbound(); mojom.ServiceProviderStub outgoingServices = new mojom.ServiceProviderStub.unbound();
_viewOwner = new mojom.ViewOwnerProxy.unbound(); _viewOwner = new mojom.ViewOwnerProxy.unbound();
viewProvider.ptr.createView(_viewOwner, incomingServices, outgoingServices); viewProvider.createView(_viewOwner, incomingServices, outgoingServices);
viewProvider.close(); viewProvider.close();
_connection = new ApplicationConnection(outgoingServices, incomingServices); _connection = new ApplicationConnection(outgoingServices, incomingServices);
} }
......
...@@ -552,7 +552,7 @@ class SemanticsServer extends mojom.SemanticsServer { ...@@ -552,7 +552,7 @@ class SemanticsServer extends mojom.SemanticsServer {
void addSemanticsListener(mojom.SemanticsListenerProxy listener) { void addSemanticsListener(mojom.SemanticsListenerProxy listener) {
// TODO(abarth): We should remove the listener when this pipe closes. // TODO(abarth): We should remove the listener when this pipe closes.
// See <https://github.com/flutter/flutter/issues/3342>. // See <https://github.com/flutter/flutter/issues/3342>.
SemanticsNode.addListener(listener.ptr); SemanticsNode.addListener(listener);
} }
@override @override
......
...@@ -36,13 +36,11 @@ const int NEW_TASK = 0x10000000; // ignore: constant_identifier_names ...@@ -36,13 +36,11 @@ const int NEW_TASK = 0x10000000; // ignore: constant_identifier_names
const int MULTIPLE_TASK = 0x08000000; // ignore: constant_identifier_names const int MULTIPLE_TASK = 0x08000000; // ignore: constant_identifier_names
ActivityProxy _initActivityProxy() { ActivityProxy _initActivityProxy() {
ActivityProxy activity = new ActivityProxy.unbound(); return shell.connectToApplicationService('mojo:android', Activity.connectToService);
shell.connectToService("mojo:android", activity);
return activity;
} }
final ActivityProxy _activityProxy = _initActivityProxy(); final ActivityProxy _activityProxy = _initActivityProxy();
final Activity activity = _activityProxy.ptr; final Activity activity = _activityProxy;
Color _cachedPrimaryColor; Color _cachedPrimaryColor;
String _cachedLabel; String _cachedLabel;
...@@ -61,5 +59,5 @@ void updateTaskDescription({ String label, Color color }) { ...@@ -61,5 +59,5 @@ void updateTaskDescription({ String label, Color color }) {
..label = label ..label = label
..primaryColor = color?.value ?? 0; ..primaryColor = color?.value ?? 0;
_activityProxy.ptr.setTaskDescription(description); _activityProxy.setTaskDescription(description);
} }
...@@ -10,9 +10,7 @@ import 'package:sky_services/flutter/platform/app_messages.mojom.dart' as mojom; ...@@ -10,9 +10,7 @@ import 'package:sky_services/flutter/platform/app_messages.mojom.dart' as mojom;
import 'shell.dart'; import 'shell.dart';
mojom.ApplicationMessagesProxy _initHostAppMessagesProxy() { mojom.ApplicationMessagesProxy _initHostAppMessagesProxy() {
mojom.ApplicationMessagesProxy proxy = new mojom.ApplicationMessagesProxy.unbound(); return shell.connectToViewAssociatedService(mojom.ApplicationMessages.connectToService);
shell.connectToViewAssociatedService(proxy);
return proxy;
} }
final mojom.ApplicationMessagesProxy _hostAppMessagesProxy = _initHostAppMessagesProxy(); final mojom.ApplicationMessagesProxy _hostAppMessagesProxy = _initHostAppMessagesProxy();
...@@ -49,7 +47,7 @@ final _ApplicationMessagesImpl _appMessages = new _ApplicationMessagesImpl(); ...@@ -49,7 +47,7 @@ final _ApplicationMessagesImpl _appMessages = new _ApplicationMessagesImpl();
class HostMessages { class HostMessages {
/// Send a message to the host application. /// Send a message to the host application.
static Future<String> sendToHost(String messageName, String message) async { static Future<String> sendToHost(String messageName, String message) async {
return (await _hostAppMessagesProxy.ptr.sendString(messageName, message)).reply; return (await _hostAppMessagesProxy.sendString(messageName, message)).reply;
} }
/// Register a callback for messages received from the host application. /// Register a callback for messages received from the host application.
......
...@@ -8,7 +8,7 @@ import 'dart:typed_data'; ...@@ -8,7 +8,7 @@ import 'dart:typed_data';
import 'package:flutter/http.dart' as http; import 'package:flutter/http.dart' as http;
import 'package:mojo/core.dart' as core; import 'package:mojo/core.dart' as core;
import 'package:mojo_services/mojo/asset_bundle/asset_bundle.mojom.dart'; import 'package:mojo_services/mojo/asset_bundle/asset_bundle.mojom.dart' as mojom;
import 'image_cache.dart'; import 'image_cache.dart';
import 'image_decoder.dart'; import 'image_decoder.dart';
...@@ -122,29 +122,29 @@ abstract class CachingAssetBundle extends AssetBundle { ...@@ -122,29 +122,29 @@ abstract class CachingAssetBundle extends AssetBundle {
/// An [AssetBundle] that loads resources from a Mojo service. /// An [AssetBundle] that loads resources from a Mojo service.
class MojoAssetBundle extends CachingAssetBundle { class MojoAssetBundle extends CachingAssetBundle {
/// Creates an [AssetBundle] interface around the given [AssetBundleProxy] Mojo service. /// Creates an [AssetBundle] interface around the given [mojom.AssetBundleProxy] Mojo service.
MojoAssetBundle(this._bundle); MojoAssetBundle(this._bundle);
/// Retrieves the asset bundle located at the given URL, unpacks it, and provides it contents. /// Retrieves the asset bundle located at the given URL, unpacks it, and provides it contents.
factory MojoAssetBundle.fromNetwork(String relativeUrl) { factory MojoAssetBundle.fromNetwork(String relativeUrl) {
AssetBundleProxy bundle = new AssetBundleProxy.unbound(); mojom.AssetBundleProxy bundle = new mojom.AssetBundleProxy.unbound();
_fetchAndUnpackBundle(relativeUrl, bundle); _fetchAndUnpackBundle(relativeUrl, bundle);
return new MojoAssetBundle(bundle); return new MojoAssetBundle(bundle);
} }
static Future<Null> _fetchAndUnpackBundle(String relativeUrl, AssetBundleProxy bundle) async { static Future<Null> _fetchAndUnpackBundle(String relativeUrl, mojom.AssetBundleProxy bundle) async {
core.MojoDataPipeConsumer bundleData = await http.readDataPipe(Uri.base.resolve(relativeUrl)); core.MojoDataPipeConsumer bundleData = await http.readDataPipe(Uri.base.resolve(relativeUrl));
AssetUnpackerProxy unpacker = new AssetUnpackerProxy.unbound(); mojom.AssetUnpackerProxy unpacker = shell.connectToApplicationService(
shell.connectToService("mojo:asset_bundle", unpacker); 'mojo:asset_bundle', mojom.AssetUnpacker.connectToService);
unpacker.ptr.unpackZipStream(bundleData, bundle); unpacker.unpackZipStream(bundleData, bundle);
unpacker.close(); unpacker.close();
} }
AssetBundleProxy _bundle; mojom.AssetBundleProxy _bundle;
@override @override
Future<core.MojoDataPipeConsumer> load(String key) async { Future<core.MojoDataPipeConsumer> load(String key) async {
return (await _bundle.ptr.getAsStream(key)).assetData; return (await _bundle.getAsStream(key)).assetData;
} }
} }
...@@ -153,7 +153,7 @@ AssetBundle _initRootBundle() { ...@@ -153,7 +153,7 @@ AssetBundle _initRootBundle() {
if (h == core.MojoHandle.INVALID) if (h == core.MojoHandle.INVALID)
return new NetworkAssetBundle(Uri.base); return new NetworkAssetBundle(Uri.base);
core.MojoHandle handle = new core.MojoHandle(h); core.MojoHandle handle = new core.MojoHandle(h);
return new MojoAssetBundle(new AssetBundleProxy.fromHandle(handle)); return new MojoAssetBundle(new mojom.AssetBundleProxy.fromHandle(handle));
} }
/// The [AssetBundle] from which this application was loaded. /// The [AssetBundle] from which this application was loaded.
......
...@@ -11,9 +11,7 @@ import 'shell.dart'; ...@@ -11,9 +11,7 @@ import 'shell.dart';
export 'package:sky_services/editing/editing.mojom.dart' show ClipboardData; export 'package:sky_services/editing/editing.mojom.dart' show ClipboardData;
mojom.ClipboardProxy _initClipboardProxy() { mojom.ClipboardProxy _initClipboardProxy() {
mojom.ClipboardProxy proxy = new mojom.ClipboardProxy.unbound(); return shell.connectToApplicationService('mojo:clipboard', mojom.Clipboard.connectToService);
shell.connectToService('mojo:clipboard', proxy);
return proxy;
} }
final mojom.ClipboardProxy _clipboardProxy = _initClipboardProxy(); final mojom.ClipboardProxy _clipboardProxy = _initClipboardProxy();
...@@ -26,10 +24,10 @@ class Clipboard { ...@@ -26,10 +24,10 @@ class Clipboard {
Clipboard._(); Clipboard._();
static void setClipboardData(mojom.ClipboardData clip) { static void setClipboardData(mojom.ClipboardData clip) {
_clipboardProxy.ptr.setClipboardData(clip); _clipboardProxy.setClipboardData(clip);
} }
static Future<mojom.ClipboardData> getClipboardData(String format) async { static Future<mojom.ClipboardData> getClipboardData(String format) async {
return (await _clipboardProxy.ptr.getClipboardData(format)).clip; return (await _clipboardProxy.getClipboardData(format)).clip;
} }
} }
...@@ -9,9 +9,7 @@ import 'package:sky_services/flutter/platform/haptic_feedback.mojom.dart' as moj ...@@ -9,9 +9,7 @@ import 'package:sky_services/flutter/platform/haptic_feedback.mojom.dart' as moj
import 'shell.dart'; import 'shell.dart';
mojom.HapticFeedbackProxy _initHapticFeedbackProxy() { mojom.HapticFeedbackProxy _initHapticFeedbackProxy() {
mojom.HapticFeedbackProxy proxy = new mojom.HapticFeedbackProxy.unbound(); return shell.connectToApplicationService('mojo:flutter_platform', mojom.HapticFeedback.connectToService);
shell.connectToService('mojo:flutter_platform', proxy);
return proxy;
} }
final mojom.HapticFeedbackProxy _hapticFeedbackProxy = _initHapticFeedbackProxy(); final mojom.HapticFeedbackProxy _hapticFeedbackProxy = _initHapticFeedbackProxy();
...@@ -39,6 +37,6 @@ class HapticFeedback { ...@@ -39,6 +37,6 @@ class HapticFeedback {
/// feedback if the device does not have a vibrator or one is disabled in /// feedback if the device does not have a vibrator or one is disabled in
/// system settings. /// system settings.
static Future<bool> vibrate() async { static Future<bool> vibrate() async {
return (await _hapticFeedbackProxy.ptr.vibrate()).success; return (await _hapticFeedbackProxy.vibrate()).success;
} }
} }
...@@ -83,10 +83,8 @@ class KeyboardHandle { ...@@ -83,10 +83,8 @@ class KeyboardHandle {
} }
mojom.KeyboardProxy _initKeyboardProxy() { mojom.KeyboardProxy _initKeyboardProxy() {
mojom.KeyboardProxy proxy = new mojom.KeyboardProxy.unbound(); return shell.connectToViewAssociatedService(mojom.Keyboard.connectToService);
shell.connectToViewAssociatedService(proxy);
return proxy;
} }
final mojom.KeyboardProxy _keyboardProxy = _initKeyboardProxy(); final mojom.KeyboardProxy _keyboardProxy = _initKeyboardProxy();
final Keyboard keyboard = new Keyboard(_keyboardProxy.ptr); final Keyboard keyboard = new Keyboard(_keyboardProxy);
...@@ -10,9 +10,7 @@ import 'package:sky_services/flutter/platform/path_provider.mojom.dart' as mojom ...@@ -10,9 +10,7 @@ import 'package:sky_services/flutter/platform/path_provider.mojom.dart' as mojom
import 'shell.dart'; import 'shell.dart';
mojom.PathProviderProxy _initPathProviderProxy() { mojom.PathProviderProxy _initPathProviderProxy() {
mojom.PathProviderProxy proxy = new mojom.PathProviderProxy.unbound(); return shell.connectToApplicationService('mojo:flutter_platform', mojom.PathProvider.connectToService);
shell.connectToService('mojo:flutter_platform', proxy);
return proxy;
} }
final mojom.PathProviderProxy _pathProviderProxy = _initPathProviderProxy(); final mojom.PathProviderProxy _pathProviderProxy = _initPathProviderProxy();
...@@ -32,7 +30,7 @@ class PathProvider { ...@@ -32,7 +30,7 @@ class PathProvider {
/// * _iOS_: `NSTemporaryDirectory()` /// * _iOS_: `NSTemporaryDirectory()`
/// * _Android_: `getCacheDir()` on the context. /// * _Android_: `getCacheDir()` on the context.
static Future<Directory> getTemporaryDirectory() async { static Future<Directory> getTemporaryDirectory() async {
return new Directory((await _pathProviderProxy.ptr.temporaryDirectory()).path); return new Directory((await _pathProviderProxy.temporaryDirectory()).path);
} }
/// Path to a directory where the application may place files that are private /// Path to a directory where the application may place files that are private
...@@ -44,6 +42,6 @@ class PathProvider { ...@@ -44,6 +42,6 @@ class PathProvider {
/// * _iOS_: `NSDocumentsDirectory` /// * _iOS_: `NSDocumentsDirectory`
/// * _Android_: The AppData directory. /// * _Android_: The AppData directory.
static Future<Directory> getApplicationDocumentsDirectory() async { static Future<Directory> getApplicationDocumentsDirectory() async {
return new Directory((await _pathProviderProxy.ptr.applicationDocumentsDirectory()).path); return new Directory((await _pathProviderProxy.applicationDocumentsDirectory()).path);
} }
} }
...@@ -10,10 +10,80 @@ import 'package:mojo/core.dart' as core; ...@@ -10,10 +10,80 @@ import 'package:mojo/core.dart' as core;
import 'package:mojo/mojo/service_provider.mojom.dart' as mojom; import 'package:mojo/mojo/service_provider.mojom.dart' as mojom;
import 'package:mojo/mojo/shell.mojom.dart' as mojom; import 'package:mojo/mojo/shell.mojom.dart' as mojom;
/// Signature for replacements for [shell.connectToService]. Implementations /// Signature for connecting to services. The generated mojom.dart code has
/// should return true if they handled the request, or false if the request /// static functions that match this signature on the interface objects. For
/// should fall through to the default requestService. /// example, the `mojom.Foo` interface has a `mojom.Foo.connectToService`
typedef bool OverrideConnectToService(String url, Object proxy); /// function that matches this signature.
typedef bindings.Proxy<dynamic> ServiceConnectionCallback(
bindings.ServiceConnector s, String url, [String serviceName]);
/// Signature for replacements for [shell.connectToApplicationService]. If the
/// function returns `null`, then [shell.connectToApplicationService] will fall
/// back to its default behavior.
typedef bindings.Proxy<dynamic> OverrideConnectToService(String url, ServiceConnectionCallback callback);
ApplicationConnection _initEmbedderConnection() {
core.MojoHandle incomingServicesHandle = new core.MojoHandle(ui.MojoServices.takeIncomingServices());
core.MojoHandle outgoingServicesHandle = new core.MojoHandle(ui.MojoServices.takeOutgoingServices());
if (!incomingServicesHandle.isValid || !outgoingServicesHandle.isValid)
return null;
mojom.ServiceProviderProxy incomingServices = new mojom.ServiceProviderProxy.fromHandle(incomingServicesHandle);
mojom.ServiceProviderStub outgoingServices = new mojom.ServiceProviderStub.fromHandle(outgoingServicesHandle);
return new ApplicationConnection(outgoingServices, incomingServices);
}
mojom.ShellProxy _takeShell() {
core.MojoHandle shellHandle = new core.MojoHandle(ui.MojoServices.takeShell());
if (!shellHandle.isValid)
return null;
return new mojom.ShellProxy.fromHandle(shellHandle);
}
mojom.ServiceProviderProxy _takeViewServices() {
core.MojoHandle services = new core.MojoHandle(ui.MojoServices.takeViewServices());
if (!services.isValid)
return null;
return new mojom.ServiceProviderProxy.fromHandle(services);
}
class _ShellServiceConnector extends bindings.ServiceConnector {
@override
void connectToService(String url, bindings.Proxy<dynamic> proxy, [String serviceName]) {
final MojoShell instance = MojoShell.instance;
if (url == null || instance._shell == null) {
// If the application URL is null, it means the service to connect
// to is one provided by the embedder.
// If the applircation URL isn't null but there's no shell, then
// ask the embedder in case it provides it. (For example, if you're
// running on Android without the Mojo shell, then you can obtain
// the media service from the embedder directly, instead of having
// to ask the media application for it.)
// This makes it easier to write an application that works both
// with and without a Mojo environment.
instance._embedderConnection?.requestService(proxy);
return;
}
mojom.ServiceProviderProxy services = new mojom.ServiceProviderProxy.unbound();
instance._shell.connectToApplication(url, services, null);
core.MojoMessagePipe pipe = new core.MojoMessagePipe();
proxy.ctrl.bind(pipe.endpoints[0]);
services.connectToService_(serviceName, pipe.endpoints[1]);
services.close();
}
}
class _ViewAssociatedServiceConnector extends bindings.ServiceConnector {
final mojom.ServiceProviderProxy _viewServices = _takeViewServices();
@override
void connectToService(String url, bindings.Proxy<dynamic> proxy, [String serviceName]) {
if (_viewServices != null) {
core.MojoMessagePipe pipe = new core.MojoMessagePipe();
proxy.ctrl.bind(pipe.endpoints[0]);
_viewServices.connectToService_(serviceName, pipe.endpoints[1]);
}
}
}
/// Manages connections with embedder-provided services. /// Manages connections with embedder-provided services.
class MojoShell { class MojoShell {
...@@ -30,24 +100,11 @@ class MojoShell { ...@@ -30,24 +100,11 @@ class MojoShell {
static MojoShell get instance => _instance; static MojoShell get instance => _instance;
static MojoShell _instance; static MojoShell _instance;
static mojom.ShellProxy _initShellProxy() {
core.MojoHandle shellHandle = new core.MojoHandle(ui.MojoServices.takeShell());
if (!shellHandle.isValid)
return null;
return new mojom.ShellProxy.fromHandle(shellHandle);
}
final mojom.Shell _shell = _initShellProxy()?.ptr;
static ApplicationConnection _initEmbedderConnection() {
core.MojoHandle incomingServicesHandle = new core.MojoHandle(ui.MojoServices.takeIncomingServices());
core.MojoHandle outgoingServicesHandle = new core.MojoHandle(ui.MojoServices.takeOutgoingServices());
if (!incomingServicesHandle.isValid || !outgoingServicesHandle.isValid)
return null;
mojom.ServiceProviderProxy incomingServices = new mojom.ServiceProviderProxy.fromHandle(incomingServicesHandle);
mojom.ServiceProviderStub outgoingServices = new mojom.ServiceProviderStub.fromHandle(outgoingServicesHandle);
return new ApplicationConnection(outgoingServices, incomingServices);
}
final ApplicationConnection _embedderConnection = _initEmbedderConnection(); final ApplicationConnection _embedderConnection = _initEmbedderConnection();
final mojom.Shell _shell = _takeShell();
final _ShellServiceConnector _shellServiceConnector = new _ShellServiceConnector();
final _ViewAssociatedServiceConnector _viewServiceConnector = new _ViewAssociatedServiceConnector();
/// Whether [connectToApplication] is able to connect to other applications. /// Whether [connectToApplication] is able to connect to other applications.
bool get canConnectToOtherApplications => _shell != null; bool get canConnectToOtherApplications => _shell != null;
...@@ -83,46 +140,21 @@ class MojoShell { ...@@ -83,46 +140,21 @@ class MojoShell {
/// and then invoke the method `bar()` on it: /// and then invoke the method `bar()` on it:
/// ///
/// ```dart /// ```dart
/// mojom.FooProxy foo = new mojom.FooProxy.unbound(); /// mojom.FooProxy foo = shell.connectToApplicationService(
/// shell.connectToService("mojo:foo", foo); /// "mojo:foo", mojom.Foo.connectToService);
/// foo.ptr.bar(); /// foo.bar();
/// ``` /// ```
/// ///
/// For examples of mojom files, see the `sky_services` package. /// For examples of mojom files, see the `sky_services` package.
/// ///
/// See also [connectToViewAssociatedService]. /// See also [connectToViewAssociatedService].
void connectToService(String url, bindings.ProxyBase proxy) { bindings.Proxy<dynamic> connectToApplicationService(String url, ServiceConnectionCallback callback) {
if (overrideConnectToService != null && overrideConnectToService(url, proxy)) bindings.Proxy<dynamic> proxy;
return; if (overrideConnectToService != null)
if (url == null || _shell == null) { proxy = overrideConnectToService(url, callback);
// If the application URL is null, it means the service to connect return proxy ?? callback(_shellServiceConnector, url);
// to is one provided by the embedder.
// If the applircation URL isn't null but there's no shell, then
// ask the embedder in case it provides it. (For example, if you're
// running on Android without the Mojo shell, then you can obtain
// the media service from the embedder directly, instead of having
// to ask the media application for it.)
// This makes it easier to write an application that works both
// with and without a Mojo environment.
_embedderConnection?.requestService(proxy);
return;
}
mojom.ServiceProviderProxy services = new mojom.ServiceProviderProxy.unbound();
_shell.connectToApplication(url, services, null);
core.MojoMessagePipe pipe = new core.MojoMessagePipe();
proxy.impl.bind(pipe.endpoints[0]);
services.ptr.connectToService(proxy.serviceName, pipe.endpoints[1]);
services.close();
} }
static mojom.ServiceProviderProxy _takeViewServices() {
core.MojoHandle services = new core.MojoHandle(ui.MojoServices.takeViewServices());
if (!services.isValid)
return null;
return new mojom.ServiceProviderProxy.fromHandle(services);
}
final mojom.ServiceProviderProxy _viewServices = _takeViewServices();
/// Attempts to connect to a service provided specifically for the current /// Attempts to connect to a service provided specifically for the current
/// view by the embedder or host platform. /// view by the embedder or host platform.
/// ///
...@@ -136,26 +168,23 @@ class MojoShell { ...@@ -136,26 +168,23 @@ class MojoShell {
/// `bar()` on it: /// `bar()` on it:
/// ///
/// ```dart /// ```dart
/// mojom.FooProxy foo = new mojom.FooProxy.unbound(); /// mojom.FooProxy foo = shell.connectToViewAssociatedService(
/// shell.connectToViewAssociatedService(foo); /// mojom.Foo.connectToService);
/// foo.ptr.bar(); /// foo.bar();
/// ``` /// ```
/// ///
/// For examples of mojom files, see the `sky_services` package. /// For examples of mojom files, see the `sky_services` package.
/// ///
/// See also [connectToService]. /// See also [connectToService].
void connectToViewAssociatedService(bindings.ProxyBase proxy) { bindings.Proxy<dynamic> connectToViewAssociatedService(ServiceConnectionCallback callback) {
if (overrideConnectToService != null && overrideConnectToService(null, proxy)) bindings.Proxy<dynamic> proxy;
return; if (overrideConnectToService != null)
if (_viewServices == null) proxy = overrideConnectToService(null, callback);
return; return proxy ?? callback(_viewServiceConnector, null);
core.MojoMessagePipe pipe = new core.MojoMessagePipe();
proxy.impl.bind(pipe.endpoints[0]);
_viewServices.ptr.connectToService(proxy.serviceName, pipe.endpoints[1]);
} }
/// Registers a service to expose to the embedder. /// Registers a service to expose to the embedder.
/// ///
/// For example, suppose a Flutter application wanted to provide a service /// For example, suppose a Flutter application wanted to provide a service
/// `Foo` to the embedder, that a mojom file declaring `Foo` was imported with /// `Foo` to the embedder, that a mojom file declaring `Foo` was imported with
/// the prefix `mojom`, that `package:mojo/core.dart` was imported with the /// the prefix `mojom`, that `package:mojo/core.dart` was imported with the
...@@ -163,7 +192,7 @@ class MojoShell { ...@@ -163,7 +192,7 @@ class MojoShell {
/// the class `MyFooImplementation`. The following code, run during the /// the class `MyFooImplementation`. The following code, run during the
/// binding initialization (i.e. during the same call stack as the call to the /// binding initialization (i.e. during the same call stack as the call to the
/// [new MojoShell] constructor) would achieve this: /// [new MojoShell] constructor) would achieve this:
/// ///
/// ```dart /// ```dart
/// shell.provideService(mojom.Foo.serviceName, (core.MojoMessagePipeEndpoint endpoint) { /// shell.provideService(mojom.Foo.serviceName, (core.MojoMessagePipeEndpoint endpoint) {
/// mojom.FooStub foo = new mojom.FooStub.fromEndpoint(endpoint); /// mojom.FooStub foo = new mojom.FooStub.fromEndpoint(endpoint);
......
...@@ -12,9 +12,7 @@ import 'shell.dart'; ...@@ -12,9 +12,7 @@ import 'shell.dart';
export 'package:sky_services/flutter/platform/system_chrome.mojom.dart' show DeviceOrientation; export 'package:sky_services/flutter/platform/system_chrome.mojom.dart' show DeviceOrientation;
mojom.SystemChromeProxy _initSystemChromeProxy() { mojom.SystemChromeProxy _initSystemChromeProxy() {
mojom.SystemChromeProxy proxy = new mojom.SystemChromeProxy.unbound(); return shell.connectToApplicationService('mojo:flutter_platform', mojom.SystemChrome.connectToService);
shell.connectToService('mojo:flutter_platform', proxy);
return proxy;
} }
final mojom.SystemChromeProxy _systemChromeProxy = _initSystemChromeProxy(); final mojom.SystemChromeProxy _systemChromeProxy = _initSystemChromeProxy();
...@@ -36,7 +34,7 @@ class SystemChrome { ...@@ -36,7 +34,7 @@ class SystemChrome {
/// boolean indicating if the orientation mask is valid and the changes /// boolean indicating if the orientation mask is valid and the changes
/// could be conveyed successfully to the embedder. /// could be conveyed successfully to the embedder.
static Future<bool> setPreferredOrientations(int deviceOrientationMask) async { static Future<bool> setPreferredOrientations(int deviceOrientationMask) async {
return (await _systemChromeProxy.ptr.setPreferredOrientations(deviceOrientationMask)).success; return (await _systemChromeProxy.setPreferredOrientations(deviceOrientationMask)).success;
} }
/// Specifies the set of overlays visible on the embedder when the /// Specifies the set of overlays visible on the embedder when the
...@@ -58,6 +56,6 @@ class SystemChrome { ...@@ -58,6 +56,6 @@ class SystemChrome {
/// If the overlay is unsupported on the platform, enabling or disabling /// If the overlay is unsupported on the platform, enabling or disabling
/// that overlay is a no-op and always return true. /// that overlay is a no-op and always return true.
static Future<bool> setEnabledSystemUIOverlays(int overlaysMask) async { static Future<bool> setEnabledSystemUIOverlays(int overlaysMask) async {
return (await _systemChromeProxy.ptr.setEnabledSystemUiOverlays(overlaysMask)).success; return (await _systemChromeProxy.setEnabledSystemUiOverlays(overlaysMask)).success;
} }
} }
...@@ -12,9 +12,7 @@ import 'shell.dart'; ...@@ -12,9 +12,7 @@ import 'shell.dart';
export 'package:sky_services/flutter/platform/system_sound.mojom.dart' show SystemSoundType; export 'package:sky_services/flutter/platform/system_sound.mojom.dart' show SystemSoundType;
mojom.SystemSoundProxy _initSystemSoundProxy() { mojom.SystemSoundProxy _initSystemSoundProxy() {
mojom.SystemSoundProxy proxy = new mojom.SystemSoundProxy.unbound(); return shell.connectToApplicationService('mojo:flutter_platform', mojom.SystemSound.connectToService);
shell.connectToService('mojo:flutter_platform', proxy);
return proxy;
} }
final mojom.SystemSoundProxy _systemChromeProxy = _initSystemSoundProxy(); final mojom.SystemSoundProxy _systemChromeProxy = _initSystemSoundProxy();
...@@ -33,6 +31,6 @@ class SystemSound { ...@@ -33,6 +31,6 @@ class SystemSound {
/// successfully conveyed to the embedder. No sound may actually play if the /// successfully conveyed to the embedder. No sound may actually play if the
/// device is muted or the sound was not available on the platform. /// device is muted or the sound was not available on the platform.
static Future<bool> play(SystemSoundType type) async { static Future<bool> play(SystemSoundType type) async {
return (await _systemChromeProxy.ptr.play(type)).success; return (await _systemChromeProxy.play(type)).success;
} }
} }
...@@ -61,9 +61,8 @@ class _RawKeyboardListenerState extends State<RawKeyboardListener> implements mo ...@@ -61,9 +61,8 @@ class _RawKeyboardListenerState extends State<RawKeyboardListener> implements mo
if (_stub != null) if (_stub != null)
return; return;
_stub = new mojom.RawKeyboardListenerStub.unbound()..impl = this; _stub = new mojom.RawKeyboardListenerStub.unbound()..impl = this;
mojom.RawKeyboardServiceProxy keyboard = new mojom.RawKeyboardServiceProxy.unbound(); mojom.RawKeyboardServiceProxy keyboard = shell.connectToViewAssociatedService(mojom.RawKeyboardService.connectToService);
shell.connectToViewAssociatedService(keyboard); keyboard.addListener(_stub);
keyboard.ptr.addListener(_stub);
keyboard.close(); keyboard.close();
} }
......
...@@ -6,7 +6,9 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -6,7 +6,9 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sky_services/editing/editing.mojom.dart' as mojom; import 'package:sky_services/editing/editing.mojom.dart' as mojom;
class MockKeyboard implements mojom.Keyboard { class MockKeyboard extends mojom.KeyboardProxy {
MockKeyboard() : super.unbound();
mojom.KeyboardClient client; mojom.KeyboardClient client;
@override @override
...@@ -28,7 +30,7 @@ void main() { ...@@ -28,7 +30,7 @@ void main() {
MockKeyboard mockKeyboard = new MockKeyboard(); MockKeyboard mockKeyboard = new MockKeyboard();
setUpAll(() { setUpAll(() {
serviceMocker.registerMockService(mojom.Keyboard.serviceName, mockKeyboard); serviceMocker.registerMockService(mockKeyboard);
}); });
void enterText(String testValue) { void enterText(String testValue) {
......
...@@ -7,7 +7,9 @@ import 'package:flutter/material.dart'; ...@@ -7,7 +7,9 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:sky_services/editing/editing.mojom.dart' as mojom; import 'package:sky_services/editing/editing.mojom.dart' as mojom;
class MockKeyboard implements mojom.Keyboard { class MockKeyboard extends mojom.KeyboardProxy {
MockKeyboard() : super.unbound();
mojom.KeyboardClient client; mojom.KeyboardClient client;
@override @override
...@@ -25,7 +27,9 @@ class MockKeyboard implements mojom.Keyboard { ...@@ -25,7 +27,9 @@ class MockKeyboard implements mojom.Keyboard {
void setEditingState(mojom.EditingState state) {} void setEditingState(mojom.EditingState state) {}
} }
class MockClipboard implements mojom.Clipboard { class MockClipboard extends mojom.ClipboardProxy {
MockClipboard() : super.unbound();
mojom.ClipboardData _clip; mojom.ClipboardData _clip;
@override @override
...@@ -41,9 +45,9 @@ class MockClipboard implements mojom.Clipboard { ...@@ -41,9 +45,9 @@ class MockClipboard implements mojom.Clipboard {
void main() { void main() {
MockKeyboard mockKeyboard = new MockKeyboard(); MockKeyboard mockKeyboard = new MockKeyboard();
serviceMocker.registerMockService(mojom.Keyboard.serviceName, mockKeyboard); serviceMocker.registerMockService(mockKeyboard);
MockClipboard mockClipboard = new MockClipboard(); MockClipboard mockClipboard = new MockClipboard();
serviceMocker.registerMockService(mojom.Clipboard.serviceName, mockClipboard); serviceMocker.registerMockService(mockClipboard);
void enterText(String testValue) { void enterText(String testValue) {
// Simulate entry of text through the keyboard. // Simulate entry of text through the keyboard.
......
...@@ -39,7 +39,7 @@ class SoundEffectStream { ...@@ -39,7 +39,7 @@ class SoundEffectStream {
/// Stop the sound effect. /// Stop the sound effect.
void stop() { void stop() {
_soundPool.ptr.stop(_streamId); _soundPool.stop(_streamId);
} }
/// True if the sound effect is paused. /// True if the sound effect is paused.
...@@ -48,9 +48,9 @@ class SoundEffectStream { ...@@ -48,9 +48,9 @@ class SoundEffectStream {
set paused(bool value) { set paused(bool value) {
_paused = value; _paused = value;
if (_paused) { if (_paused) {
_soundPool.ptr.pause(_streamId); _soundPool.pause(_streamId);
} else { } else {
_soundPool.ptr.resume(_streamId); _soundPool.resume(_streamId);
} }
} }
...@@ -59,7 +59,7 @@ class SoundEffectStream { ...@@ -59,7 +59,7 @@ class SoundEffectStream {
double _leftVolume; double _leftVolume;
set leftVolume(double value) { set leftVolume(double value) {
_leftVolume = value; _leftVolume = value;
_soundPool.ptr.setVolume(_streamId, <double>[_leftVolume, _rightVolume]); _soundPool.setVolume(_streamId, <double>[_leftVolume, _rightVolume]);
} }
/// Right volume of the sound effect, valid values are 0.0 to 1.0. /// Right volume of the sound effect, valid values are 0.0 to 1.0.
...@@ -67,7 +67,7 @@ class SoundEffectStream { ...@@ -67,7 +67,7 @@ class SoundEffectStream {
double _rightVolume; double _rightVolume;
set rightVolume(double value) { set rightVolume(double value) {
_rightVolume = value; _rightVolume = value;
_soundPool.ptr.setVolume(_streamId, <double>[_leftVolume, _rightVolume]); _soundPool.setVolume(_streamId, <double>[_leftVolume, _rightVolume]);
} }
/// The pitch of the sound effect, a value of 1.0 plays back the sound effect /// The pitch of the sound effect, a value of 1.0 plays back the sound effect
...@@ -76,7 +76,7 @@ class SoundEffectStream { ...@@ -76,7 +76,7 @@ class SoundEffectStream {
double _pitch; double _pitch;
set pitch(double value) { set pitch(double value) {
_pitch = value; _pitch = value;
_soundPool.ptr.setRate(_streamId, _pitch); _soundPool.setRate(_streamId, _pitch);
} }
} }
...@@ -86,10 +86,11 @@ class SoundEffectPlayer { ...@@ -86,10 +86,11 @@ class SoundEffectPlayer {
/// Creates a new SoundEffectPlayer with a max number of simultaneous /// Creates a new SoundEffectPlayer with a max number of simultaneous
/// streams specified. /// streams specified.
SoundEffectPlayer(int maxStreams) { SoundEffectPlayer(int maxStreams) {
MediaServiceProxy mediaService = new MediaServiceProxy.unbound(); MediaServiceProxy mediaService = shell.connectToApplicationService(
shell.connectToService("mojo:media_service", mediaService); 'mojo:media_service', MediaService.connectToService
);
_soundPool = new SoundPoolProxy.unbound(); _soundPool = new SoundPoolProxy.unbound();
mediaService.ptr.createSoundPool(_soundPool, maxStreams); mediaService.createSoundPool(_soundPool, maxStreams);
} }
SoundPoolProxy _soundPool; SoundPoolProxy _soundPool;
...@@ -98,7 +99,7 @@ class SoundEffectPlayer { ...@@ -98,7 +99,7 @@ class SoundEffectPlayer {
/// Loads a sound effect. /// Loads a sound effect.
Future<SoundEffect> load(MojoDataPipeConsumer data) async { Future<SoundEffect> load(MojoDataPipeConsumer data) async {
SoundPoolLoadResponseParams result = await _soundPool.ptr.load(data); SoundPoolLoadResponseParams result = await _soundPool.load(data);
if (result.success) if (result.success)
return new SoundEffect(result.soundId); return new SoundEffect(result.soundId);
...@@ -113,7 +114,7 @@ class SoundEffectPlayer { ...@@ -113,7 +114,7 @@ class SoundEffectPlayer {
double pitch: 1.0 double pitch: 1.0
}) async { }) async {
int streamId = _nextStreamId++; int streamId = _nextStreamId++;
SoundPoolPlayResponseParams result = await _soundPool.ptr.play( SoundPoolPlayResponseParams result = await _soundPool.play(
sound._soundId, streamId, <double>[leftVolume, rightVolume], loop, pitch sound._soundId, streamId, <double>[leftVolume, rightVolume], loop, pitch
); );
...@@ -134,9 +135,9 @@ class SoundEffectPlayer { ...@@ -134,9 +135,9 @@ class SoundEffectPlayer {
set paused(bool value) { set paused(bool value) {
_paused = value; _paused = value;
if (_paused) { if (_paused) {
_soundPool.ptr.pauseAll(); _soundPool.pauseAll();
} else { } else {
_soundPool.ptr.resumeAll(); _soundPool.resumeAll();
} }
} }
} }
...@@ -180,8 +181,9 @@ class SoundTrackPlayer { ...@@ -180,8 +181,9 @@ class SoundTrackPlayer {
/// Creates a new [SoundTrackPlayer], typically you will want to use the /// Creates a new [SoundTrackPlayer], typically you will want to use the
/// [sharedInstance] method to receive the player. /// [sharedInstance] method to receive the player.
SoundTrackPlayer() { SoundTrackPlayer() {
_mediaService = new MediaServiceProxy.unbound(); _mediaService = shell.connectToApplicationService(
shell.connectToService("mojo:media_service", _mediaService); 'mojo:media_service', MediaService.connectToService
);
} }
MediaServiceProxy _mediaService; MediaServiceProxy _mediaService;
...@@ -199,9 +201,9 @@ class SoundTrackPlayer { ...@@ -199,9 +201,9 @@ class SoundTrackPlayer {
// Create media player // Create media player
SoundTrack soundTrack = new SoundTrack(); SoundTrack soundTrack = new SoundTrack();
soundTrack._player = new MediaPlayerProxy.unbound(); soundTrack._player = new MediaPlayerProxy.unbound();
_mediaService.ptr.createPlayer(soundTrack._player); _mediaService.createPlayer(soundTrack._player);
await soundTrack._player.ptr.prepare(await pipe); await soundTrack._player.prepare(await pipe);
return soundTrack; return soundTrack;
} }
...@@ -217,28 +219,29 @@ class SoundTrackPlayer { ...@@ -217,28 +219,29 @@ class SoundTrackPlayer {
double volume: 1.0, double volume: 1.0,
double startTime: 0.0 double startTime: 0.0
}) { }) {
soundTrack._player.ptr.setLooping(loop); soundTrack._player
soundTrack._player.ptr.setVolume(volume); ..setLooping(loop)
soundTrack._player.ptr.seekTo((startTime * 1000.0).toInt()); ..setVolume(volume)
soundTrack._player.ptr.start(); ..seekTo((startTime * 1000.0).toInt())
..start();
_soundTracks.add(soundTrack); _soundTracks.add(soundTrack);
} }
/// Stops a [SoundTrack]. You may also want to call the [unload] method to /// Stops a [SoundTrack]. You may also want to call the [unload] method to
/// remove if from memory if you are not planning to play it again. /// remove if from memory if you are not planning to play it again.
void stop(SoundTrack track) { void stop(SoundTrack track) {
track._player.ptr.pause(); track._player.pause();
} }
/// Pauses all [SoundTrack]s that are currently playing. /// Pauses all [SoundTrack]s that are currently playing.
void pauseAll() { void pauseAll() {
for (SoundTrack soundTrack in _soundTracks) for (SoundTrack soundTrack in _soundTracks)
soundTrack._player.ptr.pause(); soundTrack._player.pause();
} }
/// Resumes all [SoundTrack]s that have been loaded by this player. /// Resumes all [SoundTrack]s that have been loaded by this player.
void resumeAll() { void resumeAll() {
for (SoundTrack soundTrack in _soundTracks) for (SoundTrack soundTrack in _soundTracks)
soundTrack._player.ptr.start(); soundTrack._player.start();
} }
} }
...@@ -7,6 +7,15 @@ import 'package:mojo/bindings.dart' as bindings; ...@@ -7,6 +7,15 @@ import 'package:mojo/bindings.dart' as bindings;
import 'binding.dart'; import 'binding.dart';
class _MockServiceConnector extends bindings.ServiceConnector {
String serviceName;
@override
void connectToService(String url, bindings.Proxy<dynamic> proxy, [String serviceName]) {
this.serviceName = serviceName;
}
}
/// Tests can use [ServiceMocker] to register replacement implementations /// Tests can use [ServiceMocker] to register replacement implementations
/// of Mojo services. /// of Mojo services.
class ServiceMocker { class ServiceMocker {
...@@ -16,23 +25,18 @@ class ServiceMocker { ...@@ -16,23 +25,18 @@ class ServiceMocker {
} }
// Map of interface names to mock implementations. // Map of interface names to mock implementations.
Map<String, Object> _interfaceMocks = <String, Object>{}; Map<String, bindings.Proxy<dynamic>> _interfaceMocks = <String, bindings.Proxy<dynamic>>{};
bool _connectToService(String url, bindings.ProxyBase proxy) { bindings.Proxy<dynamic> _connectToService(String url, ServiceConnectionCallback callback) {
Object mock = _interfaceMocks[proxy.serviceName]; // TODO(abarth): This is quite awkward. See <https://github.com/domokit/mojo/issues/786>.
if (mock != null) { _MockServiceConnector connector = new _MockServiceConnector();
// Replace the proxy's implementation of the service interface with the callback(connector, url);
// mock. The mojom bindings put the "ptr" field on all proxies. return _interfaceMocks[connector.serviceName];
(proxy as dynamic).ptr = mock;
return true;
} else {
return false;
}
} }
/// Provide a mock implementation for a Mojo interface. /// Provide a mock implementation for a Mojo interface.
void registerMockService(String interfaceName, Object mock) { void registerMockService(bindings.Proxy<dynamic> mock) {
_interfaceMocks[interfaceName] = mock; _interfaceMocks[mock.ctrl.serviceName] = mock;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment