mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
[fp-rs] Added bluetooth pairing button, result displayed in alert dialog.
This commit is contained in:
@@ -17,7 +17,8 @@ mod common;
|
||||
|
||||
use api::{BleAdapter, BleDevice, ClassicDevice};
|
||||
pub use common::{
|
||||
BleAddress, BleAdvertisement, BleDataTypeId, BluetoothError, ClassicAddress,
|
||||
BleAddress, BleAdvertisement, BleDataTypeId, BluetoothError,
|
||||
ClassicAddress, PairingResult,
|
||||
};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
|
||||
@@ -16,4 +16,8 @@ abstract class Rust {
|
||||
Stream<String> eventStream({dynamic hint});
|
||||
|
||||
FlutterRustBridgeTaskConstMeta get kEventStreamConstMeta;
|
||||
|
||||
Future<String> pair({dynamic hint});
|
||||
|
||||
FlutterRustBridgeTaskConstMeta get kPairConstMeta;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,22 @@ class RustImpl implements Rust {
|
||||
argNames: [],
|
||||
);
|
||||
|
||||
Future<String> pair({dynamic hint}) {
|
||||
return _platform.executeNormal(FlutterRustBridgeTask(
|
||||
callFfi: (port_) => _platform.inner.wire_pair(port_),
|
||||
parseSuccessData: _wire2api_String,
|
||||
constMeta: kPairConstMeta,
|
||||
argValues: [],
|
||||
hint: hint,
|
||||
));
|
||||
}
|
||||
|
||||
FlutterRustBridgeTaskConstMeta get kPairConstMeta =>
|
||||
const FlutterRustBridgeTaskConstMeta(
|
||||
debugName: "pair",
|
||||
argNames: [],
|
||||
);
|
||||
|
||||
void dispose() {
|
||||
_platform.dispose();
|
||||
}
|
||||
@@ -214,6 +230,18 @@ class RustWire implements FlutterRustBridgeWireBase {
|
||||
late final _wire_event_stream =
|
||||
_wire_event_streamPtr.asFunction<void Function(int)>();
|
||||
|
||||
void wire_pair(
|
||||
int port_,
|
||||
) {
|
||||
return _wire_pair(
|
||||
port_,
|
||||
);
|
||||
}
|
||||
|
||||
late final _wire_pairPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>('wire_pair');
|
||||
late final _wire_pair = _wire_pairPtr.asFunction<void Function(int)>();
|
||||
|
||||
void free_WireSyncReturn(
|
||||
WireSyncReturn ptr,
|
||||
) {
|
||||
|
||||
@@ -27,11 +27,56 @@ class HomePage extends StatelessWidget {
|
||||
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
|
||||
// Retrieve device stream from Rust side.
|
||||
stream: api.eventStream(),
|
||||
builder: (context, deviceName) {
|
||||
if (deviceName.hasData) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(deviceName.data!),
|
||||
OutlinedButton(
|
||||
onPressed: () => showDialog<String>(
|
||||
context: context,
|
||||
// Rust functions are invoked as futures.
|
||||
builder: (context) => FutureBuilder(
|
||||
future: api.pair(),
|
||||
builder: (context, pairResult) {
|
||||
return pairResult.hasData
|
||||
? AlertDialog(
|
||||
title: const Text('Pairing result'),
|
||||
content: Text(pairResult.data!),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
Navigator.pop(context, 'OK'),
|
||||
child: const Text('OK'),
|
||||
)
|
||||
],
|
||||
)
|
||||
: const AlertDialog(
|
||||
title: Text('Pairing...'),
|
||||
// Ensures the progress indicator has sensible dimensions,
|
||||
// otherwise it follows the height/width of the alert dialog.
|
||||
content: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child:
|
||||
CircularProgressIndicator(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
})),
|
||||
child: const Text('Pair'),
|
||||
),
|
||||
]);
|
||||
}
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::sync::RwLock;
|
||||
|
||||
use bluetooth::{
|
||||
api::{BleAdapter, BleDevice},
|
||||
BleDataTypeId, Platform,
|
||||
api::{BleAdapter, BleDevice, ClassicDevice},
|
||||
BleAddress, BleDataTypeId, ClassicAddress, PairingResult, Platform,
|
||||
};
|
||||
use flutter_rust_bridge::StreamSink;
|
||||
use futures::executor;
|
||||
@@ -11,6 +11,9 @@ use tracing::info;
|
||||
// Sends a device name to Flutter via `StreamSink` FFI layer.
|
||||
static NAME_STREAM: RwLock<Option<StreamSink<String>>> = RwLock::new(None);
|
||||
|
||||
// Saves the currently displayed device's address, to be used for pairing.
|
||||
static CURR_ADDRESS: RwLock<Option<BleAddress>> = RwLock::new(None);
|
||||
|
||||
/// Sets up initial constructs and infinitely polls for advertisements.
|
||||
pub fn init() {
|
||||
let run = async {
|
||||
@@ -34,12 +37,15 @@ pub fn init() {
|
||||
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);
|
||||
if name.contains("LE_WH-1000XM3") {
|
||||
match NAME_STREAM.read().unwrap().as_ref() {
|
||||
Some(stream) => {
|
||||
stream.add(name);
|
||||
let mut curr_addr = CURR_ADDRESS.write().unwrap();
|
||||
*curr_addr = Some(addr);
|
||||
}
|
||||
None => info!("Stream is None"),
|
||||
}
|
||||
None => info!("Stream is None"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,3 +61,37 @@ pub fn event_stream(s: StreamSink<String>) -> Result<(), anyhow::Error> {
|
||||
*stream = Some(s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempt classic pairing with device of address `CURR_ADDRESS`.
|
||||
pub fn pair() -> String {
|
||||
let result = match CURR_ADDRESS.read().unwrap().as_ref() {
|
||||
Some(addr) => {
|
||||
let run = async {
|
||||
let classic_addr = ClassicAddress::try_from(*addr).unwrap();
|
||||
|
||||
let classic_device = Platform::new_classic_device(classic_addr).await.unwrap();
|
||||
|
||||
match classic_device.pair().await {
|
||||
Ok(result) => match result {
|
||||
PairingResult::Success => String::from("Pairing success!"),
|
||||
PairingResult::AlreadyPaired => {
|
||||
String::from("This device is already paired.")
|
||||
}
|
||||
PairingResult::AlreadyInProgress => {
|
||||
String::from("Pairing already in progress.")
|
||||
}
|
||||
_ => String::from("Unknown result."),
|
||||
},
|
||||
Err(err) => {
|
||||
format!("Error {}", err)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
executor::block_on(run)
|
||||
}
|
||||
None => String::from("No device available to pair."),
|
||||
};
|
||||
info!(result);
|
||||
result
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ pub extern "C" fn wire_event_stream(port_: i64) {
|
||||
wire_event_stream_impl(port_)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wire_pair(port_: i64) {
|
||||
wire_pair_impl(port_)
|
||||
}
|
||||
|
||||
// Section: allocate functions
|
||||
|
||||
// Section: related functions
|
||||
|
||||
@@ -42,6 +42,16 @@ fn wire_event_stream_impl(port_: MessagePort) {
|
||||
move || move |task_callback| event_stream(task_callback.stream_sink::<_, String>()),
|
||||
)
|
||||
}
|
||||
fn wire_pair_impl(port_: MessagePort) {
|
||||
FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, String>(
|
||||
WrapInfo {
|
||||
debug_name: "pair",
|
||||
port: Some(port_),
|
||||
mode: FfiCallMode::Normal,
|
||||
},
|
||||
move || move |task_callback| Ok(pair()),
|
||||
)
|
||||
}
|
||||
// Section: wrapper structs
|
||||
|
||||
// Section: static checks
|
||||
|
||||
Reference in New Issue
Block a user