From fbc0950da4d40a0644c9eb3d38eb14a92cd67864 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Fri, 4 Mar 2016 13:36:17 -0800 Subject: [PATCH] Factor MojoShell into shell.dart Putting this code in a separate library let's services that depend only on the shell be clearer about their dependencies. --- packages/flutter/lib/animation.dart | 2 +- packages/flutter/lib/shell.dart | 99 +++++++++++++++++++ .../flutter/lib/src/rendering/binding.dart | 6 +- .../flutter/lib/src/services/binding.dart | 89 +---------------- packages/flutter/lib/src/widgets/binding.dart | 2 +- .../test/rendering/rendering_tester.dart | 4 +- 6 files changed, 111 insertions(+), 91 deletions(-) create mode 100644 packages/flutter/lib/shell.dart diff --git a/packages/flutter/lib/animation.dart b/packages/flutter/lib/animation.dart index c386df379e..ad8efec305 100644 --- a/packages/flutter/lib/animation.dart +++ b/packages/flutter/lib/animation.dart @@ -4,7 +4,7 @@ /// The Flutter animation system. /// -/// See [https://flutter.io/animations/] for an overview. +/// See for an overview. /// /// This library depends only on core Dart libraries and the `newton` package. library animation; diff --git a/packages/flutter/lib/shell.dart b/packages/flutter/lib/shell.dart new file mode 100644 index 0000000000..27256becc8 --- /dev/null +++ b/packages/flutter/lib/shell.dart @@ -0,0 +1,99 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// Manages connections with embedder-provided services. +library shell; + +import 'dart:ui' as ui; + +import 'package:mojo/application.dart'; +import 'package:mojo/bindings.dart' as bindings; +import 'package:mojo/core.dart' as core; +import 'package:mojo/mojo/service_provider.mojom.dart' as mojom; +import 'package:mojo/mojo/shell.mojom.dart' as mojom; + +/// A replacement for shell.connectToService. Implementations should return true +/// if they handled the request, or false if the request should fall through +/// to the default requestService. +typedef bool OverrideConnectToService(String url, Object proxy); + +/// Manages connections with embedder-provided services. +class MojoShell { + MojoShell() { + assert(_instance == null); + _instance = this; + } + + /// The unique instance of this class. + static MojoShell get instance => _instance; + static MojoShell _instance; + + static mojom.ShellProxy _initShellProxy() { + core.MojoHandle shellHandle = new core.MojoHandle(ui.takeShellProxyHandle()); + if (!shellHandle.isValid) + return null; + return new mojom.ShellProxy.fromHandle(shellHandle); + } + final mojom.Shell _shell = _initShellProxy()?.ptr; + + static ApplicationConnection _initEmbedderConnection() { + core.MojoHandle servicesHandle = new core.MojoHandle(ui.takeServicesProvidedByEmbedder()); + core.MojoHandle exposedServicesHandle = new core.MojoHandle(ui.takeServicesProvidedToEmbedder()); + if (!servicesHandle.isValid || !exposedServicesHandle.isValid) + return null; + mojom.ServiceProviderProxy services = new mojom.ServiceProviderProxy.fromHandle(servicesHandle); + mojom.ServiceProviderStub exposedServices = new mojom.ServiceProviderStub.fromHandle(exposedServicesHandle); + return new ApplicationConnection(exposedServices, services); + } + final ApplicationConnection _embedderConnection = _initEmbedderConnection(); + + /// Attempts to connect to an application via the Mojo shell. + ApplicationConnection connectToApplication(String url) { + 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); + } + + /// Set this to intercept calls to [connectToService()] and supply an + /// alternative implementation of a service (for example, a mock for testing). + OverrideConnectToService overrideConnectToService; + + /// Attempts to connect to a service implementing the interface for the given proxy. + /// If an application URL is specified, the service will be requested from that application. + /// Otherwise, it will be requested from the embedder (the Flutter engine). + void connectToService(String url, bindings.ProxyBase proxy) { + if (overrideConnectToService != null && overrideConnectToService(url, proxy)) + return; + if (url == null || _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. + _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(); + } + + /// Registers a service to expose to the embedder. + void provideService(String interfaceName, ServiceFactory factory) { + _embedderConnection?.provideService(interfaceName, factory); + } +} + +/// The singleton object that manages connections with embedder-provided services. +MojoShell get shell => MojoShell.instance; diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 52105fd602..8fddbf5ce9 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -19,7 +19,7 @@ import 'semantics.dart'; export 'package:flutter/gestures.dart' show HitTestResult; /// The glue between the render tree and the Flutter engine. -abstract class Renderer extends Object with Scheduler, MojoShell +abstract class Renderer extends Object with Scheduler, Services implements HitTestable { void initInstances() { @@ -67,7 +67,7 @@ abstract class Renderer extends Object with Scheduler, MojoShell void initSemantics() { SemanticsNode.onSemanticsEnabled = renderView.scheduleInitialSemantics; - provideService(mojom.SemanticsServer.serviceName, (core.MojoMessagePipeEndpoint endpoint) { + shell.provideService(mojom.SemanticsServer.serviceName, (core.MojoMessagePipeEndpoint endpoint) { mojom.SemanticsServerStub server = new mojom.SemanticsServerStub.fromEndpoint(endpoint); server.impl = new SemanticsServer(); }); @@ -116,7 +116,7 @@ void debugDumpSemanticsTree() { /// A concrete binding for applications that use the Rendering framework /// directly. This is the glue that binds the framework to the Flutter engine. -class RenderingFlutterBinding extends BindingBase with Scheduler, Gesturer, MojoShell, Renderer { +class RenderingFlutterBinding extends BindingBase with Scheduler, Gesturer, Services, Renderer { RenderingFlutterBinding({ RenderBox root }) { assert(renderView != null); renderView.child = root; diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart index 51f71aa141..ff0023ca9b 100644 --- a/packages/flutter/lib/src/services/binding.dart +++ b/packages/flutter/lib/src/services/binding.dart @@ -1,14 +1,10 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui; +import 'package:flutter/shell.dart'; -import 'package:mojo/application.dart'; -import 'package:mojo/bindings.dart' as bindings; -import 'package:mojo/core.dart' as core; -import 'package:mojo/mojo/service_provider.mojom.dart' as mojom; -import 'package:mojo/mojo/shell.mojom.dart' as mojom; +export 'package:flutter/shell.dart'; /// Base class for mixins that provide singleton services (also known as /// "bindings"). @@ -41,84 +37,9 @@ abstract class BindingBase { String toString() => '<$runtimeType>'; } -// A replacement for shell.connectToService. Implementations should return true -// if they handled the request, or false if the request should fall through -// to the default requestService. -typedef bool OverrideConnectToService(String url, Object proxy); - -abstract class MojoShell extends BindingBase { - +abstract class Services extends BindingBase { void initInstances() { super.initInstances(); - _instance = this; - } - - static MojoShell _instance; - static MojoShell get instance => _instance; - - static mojom.ShellProxy _initShellProxy() { - core.MojoHandle shellHandle = new core.MojoHandle(ui.takeShellProxyHandle()); - if (!shellHandle.isValid) - return null; - return new mojom.ShellProxy.fromHandle(shellHandle); - } - final mojom.Shell _shell = _initShellProxy()?.ptr; - - static ApplicationConnection _initEmbedderConnection() { - core.MojoHandle servicesHandle = new core.MojoHandle(ui.takeServicesProvidedByEmbedder()); - core.MojoHandle exposedServicesHandle = new core.MojoHandle(ui.takeServicesProvidedToEmbedder()); - if (!servicesHandle.isValid || !exposedServicesHandle.isValid) - return null; - mojom.ServiceProviderProxy services = new mojom.ServiceProviderProxy.fromHandle(servicesHandle); - mojom.ServiceProviderStub exposedServices = new mojom.ServiceProviderStub.fromHandle(exposedServicesHandle); - return new ApplicationConnection(exposedServices, services); - } - final ApplicationConnection _embedderConnection = _initEmbedderConnection(); - - /// Attempts to connect to an application via the Mojo shell. - ApplicationConnection connectToApplication(String url) { - 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); - } - - /// Set this to intercept calls to [connectToService()] and supply an - /// alternative implementation of a service (for example, a mock for testing). - OverrideConnectToService overrideConnectToService; - - /// Attempts to connect to a service implementing the interface for the given proxy. - /// If an application URL is specified, the service will be requested from that application. - /// Otherwise, it will be requested from the embedder (the Flutter engine). - void connectToService(String url, bindings.ProxyBase proxy) { - if (overrideConnectToService != null && overrideConnectToService(url, proxy)) - return; - if (url == null || _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. - _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(); - } - - /// Registers a service to expose to the embedder. - void provideService(String interfaceName, ServiceFactory factory) { - _embedderConnection?.provideService(interfaceName, factory); + new MojoShell(); } } -MojoShell get shell => MojoShell.instance; diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 58247e763f..0b353bc0dc 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -24,7 +24,7 @@ class BindingObserver { /// A concrete binding for applications based on the Widgets framework. /// This is the glue that binds the framework to the Flutter engine. -class WidgetFlutterBinding extends BindingBase with Scheduler, Gesturer, MojoShell, Renderer { +class WidgetFlutterBinding extends BindingBase with Scheduler, Gesturer, Services, Renderer { /// Creates and initializes the WidgetFlutterBinding. This constructor is /// idempotent; calling it a second time will just return the diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart index fb700b9cd4..6ac6287faf 100644 --- a/packages/flutter/test/rendering/rendering_tester.dart +++ b/packages/flutter/test/rendering/rendering_tester.dart @@ -26,7 +26,7 @@ enum EnginePhase { composite } -class TestRenderingFlutterBinding extends BindingBase with Scheduler, MojoShell, Renderer, Gesturer { +class TestRenderingFlutterBinding extends BindingBase with Scheduler, Services, Renderer, Gesturer { void initRenderView() { if (renderView == null) { renderView = new TestRenderView(); @@ -58,7 +58,7 @@ void layout(RenderBox box, { BoxConstraints constraints, EnginePhase phase: Engi _renderer ??= new TestRenderingFlutterBinding(); - renderer.renderView.child = null; + renderer.renderView.child = null; if (constraints != null) { box = new RenderPositionedBox( child: new RenderConstrainedBox(