discovery: Added a flutter example for discovery
The UI is pretty awful here, but I figure I should check this in since
it works and clean up the UI later. There is no v23proxy support as of
yet because it requires a newer version of mojo than flutter.
Change-Id: I890fa26c8fdf1b8b4a0921b791f7f503d98fe01f
diff --git a/.gitignore b/.gitignore
index ec6cb21..3899f02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@
/java/.gradle
/java/build/
/java/local.properties
+*.srcjar
diff --git a/example/discovery/.gitignore b/example/discovery/.gitignore
new file mode 100644
index 0000000..a7541f8
--- /dev/null
+++ b/example/discovery/.gitignore
@@ -0,0 +1,4 @@
+.pub/
+.packages/
+build/
+packages
diff --git a/example/discovery/FLUTTER_VERSION b/example/discovery/FLUTTER_VERSION
new file mode 100644
index 0000000..b01d319
--- /dev/null
+++ b/example/discovery/FLUTTER_VERSION
@@ -0,0 +1 @@
+b70a53807aca5c74c48298f68fcb6f041fedbe9a
diff --git a/example/discovery/Makefile b/example/discovery/Makefile
new file mode 100644
index 0000000..b8484e0
--- /dev/null
+++ b/example/discovery/Makefile
@@ -0,0 +1,77 @@
+ifndef DEVICE_NUM
+ DEVICE_NUM := 1
+endif
+
+DEVICE_NUM_PLUS_ONE := $(shell echo $(DEVICE_NUM) \+ 1 | bc)
+DEVICE_ID := $(shell adb devices | sed -n $(DEVICE_NUM_PLUS_ONE)p | awk '{ print $$1; }')
+DEVICE_FLAG := --target-device $(DEVICE_ID)
+
+ifneq ($(DEVICE_NUM), 1)
+ REUSE_FLAG := --reuse-servers
+endif
+
+ifdef VLOG
+ VLOG_FLAGS = --v=$(VLOG) --logtostderr=true
+endif
+
+MOJO_DEVTOOLS := $(shell jiri v23-profile env --profiles=mojo --target=arm-android MOJO_DEVTOOLS=)
+MOJO_SHELL := $(shell jiri v23-profile env --profiles=mojo --target=arm-android MOJO_SHELL=)
+
+APP_FLX_FILE := $(PWD)/build/app.flx
+DISCOVERY_MOJO_DIR := $(PWD)/packages/v23discovery/mojo_services/android
+MOJO_SHELL_CMD_PATH := /data/local/tmp/org.chromium.mojo.shell.cmd
+
+default: run
+
+.PHONY: dartanalyzer
+dartanalyzer: packages
+ dartanalyzer lib/main.dart
+
+.PHONY: dartfmt
+dartfmt: packages
+ dartfmt --overwrite lib
+
+packages: pubspec.yaml
+ pub get
+
+.PHONY: upgrade-packages
+upgrade-packages:
+ pub upgrade
+
+.PHONY: build
+build: packages
+ pub run flutter_tools build
+
+.PHONY: install-shell
+install-shell:
+ adb -s $(DEVICE_ID) install $(MOJO_SHELL)
+
+.PHONY: uninstall-shell
+uninstall-shell:
+ adb -s $(DEVICE_ID) uninstall org.chromium.mojo.shell
+
+# Usage example:
+# DEVICE_NUM=1 make run
+# DEVICE_NUM=2 make run
+run: build install-shell
+ pub run flutter_tools run_mojo \
+ --devtools-path $(MOJO_DEVTOOLS)/mojo_run \
+ --android --mojo-debug -- --enable-multiprocess \
+ --map-origin="https://discovery.mojo.v.io/=$(DISCOVERY_MOJO_DIR)" \
+ $(DEVICE_FLAG) \
+ $(REUSE_FLAG) \
+ --no-config-file
+
+# Helper targets
+run1:
+ DEVICE_NUM=1 make run
+run2:
+ DEVICE_NUM=2 make run
+run3:
+ DEVICE_NUM=3 make run
+run4:
+ DEVICE_NUM=4 make run
+
+.PHONY: clean
+clean:
+ rm -rf packages
diff --git a/example/discovery/README.md b/example/discovery/README.md
new file mode 100644
index 0000000..a24b03d
--- /dev/null
+++ b/example/discovery/README.md
@@ -0,0 +1,32 @@
+# Discovery
+
+A simple Flutter app that uses v23 discovery.
+
+# Prerequisites
+
+## Flutter
+
+A clone of https://github.com/flutter/flutter/ at the commit # specified in FLUTTER_VERSION file must be available in a directory
+called `flutter` at the same level as $JIRI_ROOT directory.
+
+## Mojo
+
+Mojo profile for Android target must be installed. You can run `jiri v23-profile install --target=arm-android mojo` to install it.
+
+## Dart
+
+Mojo profile must be installed. You can run `jiri v23-profile install dart` to install it.
+
+## Android Setup
+
+Currently Flutter requires an Android device running the Lollipop (or newer) version of the Android operating system.
+`adb` tool from Android SDK needs to be installed. Please follow instructions on setting up your android device [here](http://flutter.io/getting-started/#setting-up-your-android-device)
+
+# Running Discovery Demo
+
+Connect your Android device via USB and ensure `Android debugging` is enabled, then execute:
+```
+make run
+```
+
+If you have multiple Android devices connected, you can set the DEVICE_NUM enviroment variable to choose the device
diff --git a/example/discovery/flutter.yaml b/example/discovery/flutter.yaml
new file mode 100644
index 0000000..8f711f3
--- /dev/null
+++ b/example/discovery/flutter.yaml
@@ -0,0 +1,4 @@
+name: discovery
+material-design-icons:
+ - name: notification/tap_and_play
+ - name: action/search
diff --git a/example/discovery/lib/main.dart b/example/discovery/lib/main.dart
new file mode 100644
index 0000000..7cb605e
--- /dev/null
+++ b/example/discovery/lib/main.dart
@@ -0,0 +1,180 @@
+// Copyright 2015 The Vanadium 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 'dart:collection';
+
+import 'package:flutter/material.dart';
+import 'package:v23discovery/discovery.dart' as discovery;
+import 'package:flutter/services.dart' show shell;
+import 'package:uuid/uuid.dart';
+
+const String _discoveryMojoUrl =
+ 'https://discovery.mojo.v.io/discovery.mojo';
+
+void main() {
+ runApp(
+ new MaterialApp(
+ title: "Discovery Demo",
+ routes: <String, RouteBuilder>{
+ '/': (RouteArguments args) => new DiscoveryDemo()
+ }
+ )
+ );
+}
+
+final discovery.Client _discoveryClient =
+ new discovery.Client(shell.connectToService, _discoveryMojoUrl);
+
+class DiscoveryDemo extends StatefulComponent {
+ @override
+ State createState() => new DiscoveryDemoState();
+}
+
+final String instanceName = 'sample${new Uuid().v4()}';
+const String interfaceName = 'examples.discovery.sample';
+
+// The color of the icon to signify that the action is running.
+final highlightColor = Colors.blue[500];
+class DiscoveryDemoState extends State {
+ // The message to advertise.
+ // TODO: After v23proxy works for dart send this via rpc rather than
+ // attributes.
+ String message = 'Hello world!';
+ bool isAdvertising = false;
+ bool isScanning = false;
+ // The currently running advertisement. This is used to stop the
+ // advertisement when we are done.
+ discovery.Advertiser adv = null;
+
+ // The currently running scanner. This is used to stop the
+ // scanning when we are done.
+ discovery.Scanner scanner = null;
+ // A SplayTreeMap is used so the iteration order is stable.
+ Map<String, String> foundMessages = new SplayTreeMap();
+
+ Future _startAdvertising() async {
+ Map<String, String> attrs = new Map();
+ attrs['message'] = message;
+ var service = new discovery.Service()
+ ..attrs = attrs
+ ..interfaceName = interfaceName
+ ..instanceName = instanceName
+ // TODO put in a real endpoint here. An empty array results in an
+ // advertisement error.
+ ..addrs = ['localhost:4000'];
+ adv = await _discoveryClient.advertise(service);
+ setState(() { isAdvertising = true;});
+ }
+
+ Future _stopAdvertising() async {
+ await adv?.stop();
+ adv = null;
+ setState(() { isAdvertising = false; });
+ }
+
+ void _toggleAdvertising() {
+ if (!isAdvertising) {
+ _startAdvertising();
+ } else {
+ _stopAdvertising();
+ }
+ }
+
+ Future _maybeUpdateAdv() async {
+ if (!isAdvertising) {
+ return;
+ }
+ // Don't call _stopAdvertising so the button's background color doesn't
+ // change briefly while we update the advertisement.
+ await adv.stop();
+ await _startAdvertising();
+ }
+
+ Future _startScanning() async {
+ var query = 'v.InterfaceName = "${interfaceName}"';
+ scanner = await _discoveryClient.scan(query);
+ scanner.onUpdate.listen((update) {
+ // Ignore advertisements for this device.
+ if (update.service.instanceName == instanceName) {
+ return;
+ }
+ setState(() {
+ var instanceName = update.service.instanceName;
+ if (update.updateType == discovery.UpdateType.found) {
+ foundMessages[instanceName] = update.service.attrs['message'];
+ } else {
+ foundMessages.remove(instanceName);
+ }
+ });
+ });
+ setState(() { isScanning = true;});
+ }
+
+ Future _stopScanning() async {
+ await scanner.stop();
+ scanner = null;
+ setState(() { isScanning = false; });
+ }
+
+ void _toggleScanning() {
+ if (!isScanning) {
+ _startScanning();
+ } else {
+ _stopScanning();
+ }
+ }
+
+ // Builds the row that contains the message input and the buttons to start
+ // and stop discovery.
+ Widget _buildButtonBar() {
+ var advColor;
+ if (isAdvertising) {
+ advColor = highlightColor;
+ }
+ var advButton = new IconButton(
+ icon: 'notification/tap_and_play',
+ color: advColor,
+ onPressed: _toggleAdvertising
+ );
+
+
+ var scanColor;
+ if (isScanning) {
+ scanColor = highlightColor;
+ }
+ var scanButton = new IconButton(
+ icon: 'action/search',
+ color: scanColor,
+ onPressed: _toggleScanning
+ );
+
+ var input = new Input(
+ initialValue: message,
+ onChanged: (String value) {
+ message = value;
+ _maybeUpdateAdv();
+ });
+ return new Row(
+ children: [
+ new Text('Message'),
+ new Flexible(child: input), advButton, scanButton]);
+ }
+
+ Widget build(BuildContext context) {
+ List<Widget> children = [_buildButtonBar()];
+ foundMessages.forEach((k, v) {
+ children.add(new Text('${k}: ${foundMessages[k]}', key:new Key(k)));
+ });
+
+ return new Scaffold(
+ toolBar: new ToolBar(
+ center: new Text("Discovery Demo")
+ ),
+ body: new Material(
+ child: new Column(children: children)
+ )
+ );
+ }
+}
diff --git a/example/discovery/pubspec.yaml b/example/discovery/pubspec.yaml
new file mode 100644
index 0000000..09f014c
--- /dev/null
+++ b/example/discovery/pubspec.yaml
@@ -0,0 +1,10 @@
+name: discovery
+description: A minimal Flutter project.
+dependencies:
+ flutter:
+ path: ../../../../../../flutter/packages/flutter
+ v23discovery: ">=0.0.12 <0.1.0"
+ uuid: any
+dev_dependencies:
+ flutter_tools:
+ path: "../../../../../flutter/packages/flutter_tools"
diff --git a/java/generated-src/mojom/vanadium/discovery.mojom.srcjar b/java/generated-src/mojom/vanadium/discovery.mojom.srcjar
deleted file mode 100644
index ce1cada..0000000
--- a/java/generated-src/mojom/vanadium/discovery.mojom.srcjar
+++ /dev/null
Binary files differ