diff --git a/fastpair/rust/demo/lib/bridge_definitions.dart b/fastpair/rust/demo/lib/bridge_definitions.dart index 9468e02f..6a1b418f 100644 --- a/fastpair/rust/demo/lib/bridge_definitions.dart +++ b/fastpair/rust/demo/lib/bridge_definitions.dart @@ -9,7 +9,11 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; import 'package:uuid/uuid.dart'; abstract class Rust { - Future hello({dynamic hint}); + Future init({dynamic hint}); - FlutterRustBridgeTaskConstMeta get kHelloConstMeta; + FlutterRustBridgeTaskConstMeta get kInitConstMeta; + + Stream eventStream({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kEventStreamConstMeta; } diff --git a/fastpair/rust/demo/lib/bridge_generated.dart b/fastpair/rust/demo/lib/bridge_generated.dart index 2c075cb7..c057e0a1 100644 --- a/fastpair/rust/demo/lib/bridge_generated.dart +++ b/fastpair/rust/demo/lib/bridge_generated.dart @@ -25,19 +25,35 @@ class RustImpl implements Rust { factory RustImpl.wasm(FutureOr module) => RustImpl(module as ExternalLibrary); RustImpl.raw(this._platform); - Future hello({dynamic hint}) { + Future init({dynamic hint}) { return _platform.executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => _platform.inner.wire_hello(port_), - parseSuccessData: _wire2api_String, - constMeta: kHelloConstMeta, + callFfi: (port_) => _platform.inner.wire_init(port_), + parseSuccessData: _wire2api_unit, + constMeta: kInitConstMeta, argValues: [], hint: hint, )); } - FlutterRustBridgeTaskConstMeta get kHelloConstMeta => + FlutterRustBridgeTaskConstMeta get kInitConstMeta => const FlutterRustBridgeTaskConstMeta( - debugName: "hello", + debugName: "init", + argNames: [], + ); + + Stream eventStream({dynamic hint}) { + return _platform.executeStream(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_event_stream(port_), + parseSuccessData: _wire2api_String, + constMeta: kEventStreamConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kEventStreamConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "event_stream", argNames: [], ); @@ -57,6 +73,10 @@ class RustImpl implements Rust { Uint8List _wire2api_uint_8_list(dynamic raw) { return raw as Uint8List; } + + void _wire2api_unit(dynamic raw) { + return; + } } // Section: api2wire @@ -168,17 +188,31 @@ class RustWire implements FlutterRustBridgeWireBase { late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr .asFunction)>(); - void wire_hello( + void wire_init( int port_, ) { - return _wire_hello( + return _wire_init( port_, ); } - late final _wire_helloPtr = - _lookup>('wire_hello'); - late final _wire_hello = _wire_helloPtr.asFunction(); + late final _wire_initPtr = + _lookup>('wire_init'); + late final _wire_init = _wire_initPtr.asFunction(); + + void wire_event_stream( + int port_, + ) { + return _wire_event_stream( + port_, + ); + } + + late final _wire_event_streamPtr = + _lookup>( + 'wire_event_stream'); + late final _wire_event_stream = + _wire_event_streamPtr.asFunction(); void free_WireSyncReturn( WireSyncReturn ptr, diff --git a/fastpair/rust/demo/lib/main.dart b/fastpair/rust/demo/lib/main.dart index 45f354dc..5ce3f31d 100644 --- a/fastpair/rust/demo/lib/main.dart +++ b/fastpair/rust/demo/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:demo/rust.dart'; void main() { + api.init(); runApp(const FastPairApp()); } @@ -23,22 +24,19 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) => Scaffold( - appBar: AppBar( - title: const Text("Fast Pair"), + appBar: AppBar(title: const Text("Fast Pair")), + body: Center( + child: StreamBuilder( + // All Rust functions are called as Future's + stream: api.eventStream(), // The Rust function we are calling. + builder: (context, data) { + if (data.hasData) { + return Text(data.data!); // The string to display + } + return const Center( + child: CircularProgressIndicator(), + ); + }, ), - body: Center( - child: FutureBuilder( - // All Rust functions are called as Future's - future: api.hello(), // The Rust function we are calling. - builder: (context, data) { - if (data.hasData) { - return Text(data.data!); // The string to display - } - return const Center( - child: CircularProgressIndicator(), - ); - }, - ), - ), - ); + )); } diff --git a/fastpair/rust/demo/rust/Cargo.toml b/fastpair/rust/demo/rust/Cargo.toml index 41d5928c..20d9a17c 100644 --- a/fastpair/rust/demo/rust/Cargo.toml +++ b/fastpair/rust/demo/rust/Cargo.toml @@ -9,4 +9,8 @@ edition = "2021" crate-type = ["lib", "cdylib", "staticlib"] [dependencies] +anyhow = "1.0" +bluetooth = { version = "0.1", path = "../../bluetooth" } flutter_rust_bridge = "1" +futures = { version = "0.3", features = ["executor"] } +tracing = "0.1.37" diff --git a/fastpair/rust/demo/rust/src/api.rs b/fastpair/rust/demo/rust/src/api.rs index 812479a2..dd9ff2d7 100644 --- a/fastpair/rust/demo/rust/src/api.rs +++ b/fastpair/rust/demo/rust/src/api.rs @@ -1,3 +1,57 @@ -pub fn hello() -> String { - String::from("Rust says hi!") +use std::sync::RwLock; + +use bluetooth::{ + api::{BleAdapter, BleDevice}, + BleDataTypeId, Platform, +}; +use flutter_rust_bridge::StreamSink; +use futures::executor; +use tracing::info; + +// Sends a device name to Flutter via `StreamSink` FFI layer. +static NAME_STREAM: RwLock>> = RwLock::new(None); + +/// Sets up initial constructs and infinitely polls for advertisements. +pub fn init() { + let run = async { + info!("start making adapter"); + + let mut adapter = Platform::default_adapter().await.unwrap(); + adapter.start_scan().unwrap(); + + let datatype_selector = vec![BleDataTypeId::ServiceData16BitUuid]; + loop { + let advertisement = adapter + .next_advertisement(Some(&datatype_selector)) + .await + .unwrap(); + + for service_data in advertisement.service_data_16bit_uuid().unwrap() { + let uuid = service_data.uuid(); + // This is a Fast Pair device. + if uuid == 0x2cfe { + let addr = advertisement.address(); + let ble_device = Platform::new_ble_device(addr).await.unwrap(); + let name = ble_device.name().unwrap(); + info!("device: {}", name); + + match NAME_STREAM.read().unwrap().as_ref() { + Some(s) => { + s.add(name); + } + None => info!("Stream is None"), + } + } + } + } + }; + + executor::block_on(run) +} + +/// Sets up `StreamSink` for Dart-Rust FFI. +pub fn event_stream(s: StreamSink) -> Result<(), anyhow::Error> { + let mut stream = NAME_STREAM.write().unwrap(); + *stream = Some(s); + Ok(()) } diff --git a/fastpair/rust/demo/rust/src/bridge_generated.io.rs b/fastpair/rust/demo/rust/src/bridge_generated.io.rs index 5bc455d3..e80e9895 100644 --- a/fastpair/rust/demo/rust/src/bridge_generated.io.rs +++ b/fastpair/rust/demo/rust/src/bridge_generated.io.rs @@ -2,8 +2,13 @@ use super::*; // Section: wire functions #[no_mangle] -pub extern "C" fn wire_hello(port_: i64) { - wire_hello_impl(port_) +pub extern "C" fn wire_init(port_: i64) { + wire_init_impl(port_) +} + +#[no_mangle] +pub extern "C" fn wire_event_stream(port_: i64) { + wire_event_stream_impl(port_) } // Section: allocate functions diff --git a/fastpair/rust/demo/rust/src/bridge_generated.rs b/fastpair/rust/demo/rust/src/bridge_generated.rs index 710e8db5..1d2f5bd8 100644 --- a/fastpair/rust/demo/rust/src/bridge_generated.rs +++ b/fastpair/rust/demo/rust/src/bridge_generated.rs @@ -22,14 +22,24 @@ use std::sync::Arc; // Section: wire functions -fn wire_hello_impl(port_: MessagePort) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, String>( +fn wire_init_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( WrapInfo { - debug_name: "hello", + debug_name: "init", port: Some(port_), mode: FfiCallMode::Normal, }, - move || move |task_callback| Ok(hello()), + move || move |task_callback| Ok(init()), + ) +} +fn wire_event_stream_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( + WrapInfo { + debug_name: "event_stream", + port: Some(port_), + mode: FfiCallMode::Stream, + }, + move || move |task_callback| event_stream(task_callback.stream_sink::<_, String>()), ) } // Section: wrapper structs