[dart sdk] Move lib.app.dart#Services to the Dart SDK

Under a new namespace fuchsia_services/services#ServicesConnector

Test:
Updated and ran examples/fidl/echo_client_async.dart
 fx shell run fuchsia-pkg://fuchsia.com/echo_client_async_dart#meta/echo_client_async_dart.cmx

Change-Id: Ia15aec44ade1f2a613c60044f64a2622d912de02
diff --git a/examples/fidl/echo_client_async_dart/BUILD.gn b/examples/fidl/echo_client_async_dart/BUILD.gn
index a18f463..7c6ee08 100644
--- a/examples/fidl/echo_client_async_dart/BUILD.gn
+++ b/examples/fidl/echo_client_async_dart/BUILD.gn
@@ -21,6 +21,6 @@
     "//garnet/examples/fidl/services:echo2",
     "//garnet/public/fidl/fuchsia.sys",
     "//topaz/public/dart/fidl",
-    "//topaz/public/lib/app/dart",
+    "//topaz/public/dart/fuchsia_services",
   ]
 }
diff --git a/examples/fidl/echo_client_async_dart/lib/main.dart b/examples/fidl/echo_client_async_dart/lib/main.dart
index 2e3bd0b..badc64b 100644
--- a/examples/fidl/echo_client_async_dart/lib/main.dart
+++ b/examples/fidl/echo_client_async_dart/lib/main.dart
@@ -3,34 +3,38 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'package:fidl_fidl_examples_echo/fidl_async.dart';
-import 'package:lib.app.dart/app_async.dart';
+import 'package:fidl_fidl_examples_echo/fidl_async.dart' as fidl_echo;
+import 'package:fuchsia_services/services.dart';
 import 'package:fidl_fuchsia_sys/fidl_async.dart' show LaunchInfo;
 import 'package:fuchsia/fuchsia.dart' show exit;
 
-StartupContext _context;
-EchoProxy _echo;
-
 Future<Null> main(List<String> args) async {
-  String server =
+  String serverUrl =
       'fuchsia-pkg://fuchsia.com/echo_server_async_dart#meta/echo_server_async_dart.cmx';
   if (args.length >= 2 && args[0] == '--server') {
-    server = args[1];
+    serverUrl = args[1];
   }
 
-  _context = new StartupContext.fromStartupInfo();
+  final context = StartupContext.fromStartupInfo();
+  final servicesConnector = ServicesConnector();
 
-  final Services services = new Services();
-  final LaunchInfo launchInfo =
-      new LaunchInfo(url: server, directoryRequest: services.request());
+  // Connect. The destination server is specified, and we request for it to be
+  // started if it wasn't already.
+  final launchInfo =
+      LaunchInfo(url: serverUrl, directoryRequest: servicesConnector.request());
+  // Creates a new instance of the component described by launchInfo.
+  await context.launcher.createComponent(launchInfo, null);
 
-  await _context.launcher.createComponent(launchInfo, null);
+  // Bind. We bind EchoProxy, a generated proxy class, to the remote Echo
+  // service.
+  final _echo = fidl_echo.EchoProxy();
+  _echo.ctrl.bind(await servicesConnector
+      .connectToServiceByName<fidl_echo.Echo>(fidl_echo.Echo.$serviceName));
 
-  _echo = new EchoProxy();
-  _echo.ctrl
-      .bind(await services.connectToServiceByName<Echo>(Echo.$serviceName));
-
+  // Invoke echoString with a value and print it's response.
   final response = await _echo.echoString('hello');
   print('***** Response: $response');
+
+  // Shutdown, exit this Echo client
   exit(0);
 }
diff --git a/examples/fidl/echo_server_async_dart/lib/main.dart b/examples/fidl/echo_server_async_dart/lib/main.dart
index 2796607..83f602c 100644
--- a/examples/fidl/echo_server_async_dart/lib/main.dart
+++ b/examples/fidl/echo_server_async_dart/lib/main.dart
@@ -5,34 +5,33 @@
 import 'dart:async';
 
 import 'package:fidl/fidl.dart';
-import 'package:fidl_fidl_examples_echo/fidl_async.dart';
+import 'package:fidl_fidl_examples_echo/fidl_async.dart' as fidl_echo;
 import 'package:lib.app.dart/app_async.dart';
 
-bool quiet = false;
+bool _quiet = false;
 
-class _EchoImpl extends Echo {
-  final EchoBinding _binding = new EchoBinding();
+class _EchoImpl extends fidl_echo.Echo {
+  final _binding = fidl_echo.EchoBinding();
 
-  void bind(InterfaceRequest<Echo> request) {
+  void bind(InterfaceRequest<fidl_echo.Echo> request) {
     _binding.bind(this, request);
   }
 
   @override
   Future<String> echoString(String value) async {
-    if (!quiet) {
+    if (!_quiet) {
       print('EchoString: $value');
     }
     return value;
   }
 }
 
-StartupContext _context;
-_EchoImpl _echo;
-
 void main(List<String> args) {
-  quiet = args.contains('-q');
-  _context = new StartupContext.fromStartupInfo();
-  _echo = new _EchoImpl();
-  _context.outgoingServices
-      .addServiceForName<Echo>(_echo.bind, Echo.$serviceName);
+  _quiet = args.contains('-q');
+
+  final context = StartupContext.fromStartupInfo();
+  final echo = _EchoImpl();
+
+  context.outgoingServices.addServiceForName<fidl_echo.Echo>(
+      echo.bind, fidl_echo.Echo.$serviceName);
 }
diff --git a/public/dart/fuchsia_services/BUILD.gn b/public/dart/fuchsia_services/BUILD.gn
index f4c4fd7..b582aa7 100644
--- a/public/dart/fuchsia_services/BUILD.gn
+++ b/public/dart/fuchsia_services/BUILD.gn
@@ -25,6 +25,7 @@
     "//topaz/public/dart/fidl",
     "//topaz/public/dart/fuchsia",
     "//topaz/public/dart/zircon",
+    "//zircon/public/fidl/fuchsia-io",
   ]
 }
 
diff --git a/public/dart/fuchsia_services/lib/services.dart b/public/dart/fuchsia_services/lib/services.dart
index f7b601c..08bfd10 100644
--- a/public/dart/fuchsia_services/lib/services.dart
+++ b/public/dart/fuchsia_services/lib/services.dart
@@ -6,4 +6,5 @@
 export 'src/environment_service_connection.dart';
 export 'src/service_connection.dart';
 export 'src/service_provider_impl.dart';
+export 'src/services_connector.dart';
 export 'src/startup_context.dart';
diff --git a/public/dart/fuchsia_services/lib/src/services_connector.dart b/public/dart/fuchsia_services/lib/src/services_connector.dart
new file mode 100644
index 0000000..0777534
--- /dev/null
+++ b/public/dart/fuchsia_services/lib/src/services_connector.dart
@@ -0,0 +1,69 @@
+// Copyright 2019 The Fuchsia 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:async';
+
+import 'package:fidl/fidl.dart';
+import 'package:fidl_fuchsia_io/fidl_async.dart';
+import 'package:zircon/zircon.dart';
+
+/// Facilitate the ability to connect to services outside of the Modular
+/// Framework, for example via a command-line tool.
+///
+/// The user is responsible to launch a component and wire up a connection
+/// between the new launched component and the request returned from this
+/// [ServicesConnection.request()]. This is typically done using
+/// [StartupContext#launcher].
+///
+/// For Module Framework APIs see `package:fuchsia_modular`
+class ServicesConnector {
+  DirectoryProxy _dirProxy;
+
+  /// Creates a interface request, binds one of the channels to this object, and
+  /// returns the other channel.
+  ///
+  /// Note: previously returned [Channel] will no longer be associate with this
+  /// object.
+  Channel request() {
+    _dirProxy = DirectoryProxy();
+    return _dirProxy.ctrl.request().passChannel();
+  }
+
+  /// Connects the most recently returned [Channel] from [request()] with the
+  /// provided services represented by its [controller].
+  Future<void> connectToService<T>(ProxyController<T> controller) async {
+    final String serviceName = controller.$serviceName;
+    if (serviceName == null) {
+      throw Exception(
+          "${controller.$interfaceName}'s controller.\$serviceName must "
+          'not be null. Check the FIDL file for a missing [Discoverable]');
+    }
+    await _open(serviceName,
+        InterfaceRequest<Node>(controller.request().passChannel()));
+  }
+
+  /// Connects the most recently returned [Channel] from [request()] with the
+  /// provided services represented by its [serviceName].
+  Future<InterfaceHandle<T>> connectToServiceByName<T>(
+      String serviceName) async {
+    final ChannelPair pair = ChannelPair();
+    await _open(serviceName, InterfaceRequest<Node>(pair.first));
+    return InterfaceHandle<T>(pair.second);
+  }
+
+  /// Terminates connection and return Zircon status.
+  Future<int> close() async {
+    return _dirProxy.close();
+  }
+
+  // Open a new object relative to this directory object
+  Future<void> _open(String serviceName, InterfaceRequest<Node> object) async {
+    // connection flags for service: can read & write from target object.
+    const int _openFlags = openRightReadable | openRightWritable;
+    // 0755
+    const int _openMode = 0x1ED;
+
+    return _dirProxy.open(_openFlags, _openMode, serviceName, object);
+  }
+}
diff --git a/public/lib/app/dart/app.dart b/public/lib/app/dart/app.dart
index c0ffc14..0d3c09b 100644
--- a/public/lib/app/dart/app.dart
+++ b/public/lib/app/dart/app.dart
@@ -10,6 +10,7 @@
 import 'package:fidl_fuchsia_io/fidl.dart';
 import 'package:zircon/zircon.dart';
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 class StartupContext {
   static StartupContext _context;
 
@@ -71,6 +72,7 @@
   }
 }
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 void connectToService<T>(
     ServiceProvider serviceProvider, ProxyController<T> controller) {
   final String serviceName = controller.$serviceName;
@@ -80,6 +82,7 @@
       serviceName, controller.request().passChannel());
 }
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 InterfaceHandle<T> connectToServiceByName<T>(
     ServiceProvider serviceProvider, String serviceName) {
   final ChannelPair pair = new ChannelPair();
@@ -93,6 +96,7 @@
 
 typedef _ServiceConnectorThunk = void Function(Channel channel);
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 class ServiceProviderImpl extends ServiceProvider {
   final ServiceProviderBinding _binding = new ServiceProviderBinding();
 
@@ -127,7 +131,8 @@
     }
   }
 }
- 
+
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 class Services {
   DirectoryProxy _proxy;
   static const int _openFlags =
diff --git a/public/lib/app/dart/app_async.dart b/public/lib/app/dart/app_async.dart
index ff47012..d61504f 100644
--- a/public/lib/app/dart/app_async.dart
+++ b/public/lib/app/dart/app_async.dart
@@ -13,6 +13,7 @@
 
 import 'app.dart' as sync_app;
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 class StartupContext {
   static StartupContext _context;
 
@@ -73,6 +74,7 @@
   }
 }
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 Future<void> connectToService<T>(
     ServiceProvider serviceProvider, AsyncProxyController<T> controller) async {
   final String serviceName = controller.$serviceName;
@@ -85,6 +87,7 @@
       serviceName, controller.request().passChannel());
 }
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 InterfaceHandle<T> connectToServiceByName<T>(
     ServiceProvider serviceProvider, String serviceName) {
   final ChannelPair pair = new ChannelPair();
@@ -98,6 +101,7 @@
 
 typedef _ServiceConnectorThunk = void Function(Channel channel);
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 class ServiceProviderImpl extends ServiceProvider {
   final ServiceProviderBinding _binding = new ServiceProviderBinding();
 
@@ -134,6 +138,7 @@
   }
 }
 
+/// Deprecated! Use package:fuchsia_services/services.dart instead
 class Services {
   DirectoryProxy _proxy;
   static const int _openFlags =