diff --git a/src/BlueControl.uwp/App.xaml.cs b/src/BlueControl.uwp/App.xaml.cs index 993a1e7..72a7f66 100644 --- a/src/BlueControl.uwp/App.xaml.cs +++ b/src/BlueControl.uwp/App.xaml.cs @@ -1,4 +1,6 @@ -using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Toolkit.Mvvm.DependencyInjection; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -39,6 +41,15 @@ namespace BlueControl.uwp /// Details about the launch request and process. protected override void OnLaunched(LaunchActivatedEventArgs e) { + + Ioc.Default.ConfigureServices( + new ServiceCollection() + .AddSingleton((input) => new Services.UiShellService(Window.Current.Dispatcher)) + .AddSingleton() + .BuildServiceProvider()); + + + Frame rootFrame = Window.Current.Content as Frame; // Do not repeat app initialization when the Window already has content, diff --git a/src/BlueControl.uwp/BlueControl.uwp.csproj b/src/BlueControl.uwp/BlueControl.uwp.csproj index 9113d68..0e597f4 100644 --- a/src/BlueControl.uwp/BlueControl.uwp.csproj +++ b/src/BlueControl.uwp/BlueControl.uwp.csproj @@ -123,6 +123,10 @@ MainPage.xaml + + + + @@ -151,9 +155,21 @@ + + 6.0.0 + 6.2.12 + + 7.1.1 + + + 2.0.1 + + + + 14.0 diff --git a/src/BlueControl.uwp/MainPage.xaml b/src/BlueControl.uwp/MainPage.xaml index 16726b1..f29d005 100644 --- a/src/BlueControl.uwp/MainPage.xaml +++ b/src/BlueControl.uwp/MainPage.xaml @@ -6,7 +6,20 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" - Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> + xmlns:viewModels="using:BlueControl.uwp.ViewModels" + Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" + xmlns:interactivity="using:Microsoft.Xaml.Interactivity" + xmlns:core="using:Microsoft.Xaml.Interactions.Core" + > + + + + + + + + + diff --git a/src/BlueControl.uwp/MainPage.xaml.cs b/src/BlueControl.uwp/MainPage.xaml.cs index 606f178..e71230d 100644 --- a/src/BlueControl.uwp/MainPage.xaml.cs +++ b/src/BlueControl.uwp/MainPage.xaml.cs @@ -28,13 +28,13 @@ namespace BlueControl.uwp /// public sealed partial class MainPage : Page { - private ViewModels.MainPageViewModel vm = new ViewModels.MainPageViewModel(); + //private ViewModels.MainPageViewModel vm = new ViewModels.MainPageViewModel(); public MainPage() { - this.vm.StaDispatcher = this.Dispatcher; - this.DataContext = vm; + //this.vm.StaDispatcher = this.Dispatcher; + //this.DataContext = vm; this.InitializeComponent(); - this.Loading += async (sender, args) => await vm.ReloadAsync(); + //this.Loading += async (sender, args) => await vm.ReloadAsync(); } } diff --git a/src/BlueControl.uwp/Services/BluetoothService.cs b/src/BlueControl.uwp/Services/BluetoothService.cs new file mode 100644 index 0000000..9fdb3f1 --- /dev/null +++ b/src/BlueControl.uwp/Services/BluetoothService.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Devices.Bluetooth; +using Windows.Devices.Bluetooth.Advertisement; +using Windows.Devices.Enumeration; + +namespace BlueControl.uwp.Services +{ + public class BluetoothService : IBluetoothService + { + private bool control = false; + public BluetoothService() + { + + + + } + + private BluetoothLEAdvertisementWatcher bleWatcher = null; + public async Task IsConnectedAsync(string deviceName) + { + return (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromConnectionStatus(BluetoothConnectionStatus.Connected)) where x.Name == deviceName select x).Any(); + } + + public async Task IsPairedAsync(string deviceName) + { + return (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)) where x.Name == deviceName select x).Any(); + } + + public async Task UnpairAsync(string deviceName) + { + var device = (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)) where x.Name == deviceName select x).FirstOrDefault(); + if (device != null) + await device.Pairing.UnpairAsync(); + } + + private Action pinCreatedCallBack = null; + private void Custom_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args) + { + + if (this.pinCreatedCallBack != null) pinCreatedCallBack(args.Pin); + args.Accept(args.Pin); + } + + public async Task StartAutoPairingAsync(string deviceName, Action onFoundTryingToPair, Action onPinCreated, Action onSuccess, Action onError) + { + pinCreatedCallBack = onPinCreated; + + if (this.bleWatcher == null) + { + this.bleWatcher = new BluetoothLEAdvertisementWatcher(); + this.bleWatcher.Received += async (sender, args) => + { + try + { + if (!args.IsConnectable || control == true) return; + control = true; + var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress); + if (dev.Name == deviceName && dev.DeviceInformation.Pairing.CanPair) + { + if (onFoundTryingToPair != null) onFoundTryingToPair(); + + System.Threading.Thread.Sleep(3000); + dev.DeviceInformation.Pairing.Custom.PairingRequested += Custom_PairingRequested; + var t = await dev.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.DisplayPin, DevicePairingProtectionLevel.Encryption); + if (t.Status == DevicePairingResultStatus.Paired) + { + this.bleWatcher.Stop(); + if (onSuccess != null) onSuccess(); + } + else + if (onError != null) onError(); + } + } + catch { } + control = false; + + }; + + } + this.bleWatcher.Start(); + } + + + } +} diff --git a/src/BlueControl.uwp/Services/IBluetoothService.cs b/src/BlueControl.uwp/Services/IBluetoothService.cs new file mode 100644 index 0000000..2c64f61 --- /dev/null +++ b/src/BlueControl.uwp/Services/IBluetoothService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlueControl.uwp.Services +{ + public interface IBluetoothService + { + Task IsConnectedAsync(string deviceName); + Task IsPairedAsync(string deviceName); + Task UnpairAsync(string deviceName); + Task StartAutoPairingAsync(string deviceName, Action onFoundTryingToPair, Action onPinCreated, Action onSuccess, Action onError); + + + } +} diff --git a/src/BlueControl.uwp/Services/IShellService.cs b/src/BlueControl.uwp/Services/IShellService.cs new file mode 100644 index 0000000..f9c7193 --- /dev/null +++ b/src/BlueControl.uwp/Services/IShellService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlueControl.uwp.Services +{ + public interface IShellService + { + Task UiStaRunAsync(Action action); + void CloseApplication(); + } +} diff --git a/src/BlueControl.uwp/Services/UiShellService.cs b/src/BlueControl.uwp/Services/UiShellService.cs new file mode 100644 index 0000000..161f7b4 --- /dev/null +++ b/src/BlueControl.uwp/Services/UiShellService.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlueControl.uwp.Services +{ + public class UiShellService : IShellService + { + public async Task UiStaRunAsync(Action action) + { + if (StaDispatcher != null) + await StaDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => action()); + } + + public Windows.UI.Core.CoreDispatcher StaDispatcher { get; set; } + + public UiShellService(Windows.UI.Core.CoreDispatcher dispacher) + { + this.StaDispatcher = dispacher; + } + + public void CloseApplication() + { + App.Current.Exit(); + } + + } +} diff --git a/src/BlueControl.uwp/ViewModels/MainPageViewModel.cs b/src/BlueControl.uwp/ViewModels/MainPageViewModel.cs index d696252..072f77a 100644 --- a/src/BlueControl.uwp/ViewModels/MainPageViewModel.cs +++ b/src/BlueControl.uwp/ViewModels/MainPageViewModel.cs @@ -1,9 +1,12 @@ -using System; +using Microsoft.Toolkit.Mvvm.DependencyInjection; +using Microsoft.Toolkit.Mvvm.Input; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Input; using Windows.Devices.Bluetooth; using Windows.Devices.Bluetooth.Advertisement; using Windows.Devices.Enumeration; @@ -14,22 +17,18 @@ namespace BlueControl.uwp.ViewModels public class MainPageViewModel : INotifyPropertyChanged { private const string SURFACE_KEYBOARD_NAME = "Surface Keyboard"; - private readonly BluetoothLEAdvertisementWatcher bleWatcher = new BluetoothLEAdvertisementWatcher(); - private bool control = false; - public Windows.UI.Core.CoreDispatcher StaDispatcher { get; set; } - public async Task StaExecuteAsync(Action action) - { - if (StaDispatcher != null) - await StaDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => action()); - } + + + + private void CloseApplication(TimeSpan delta) { var dispatcherTimer = new DispatcherTimer(); - dispatcherTimer.Tick += (o, e) => App.Current.Exit(); + dispatcherTimer.Tick += (o, e) => ShellService.CloseApplication(); dispatcherTimer.Interval = delta; dispatcherTimer.Start(); } @@ -40,48 +39,21 @@ namespace BlueControl.uwp.ViewModels } - private void Custom_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args) - { - StaExecuteAsync(() => this.Text = "Pin: " + Environment.NewLine + args.Pin); - args.Accept(args.Pin); - } + private readonly Services.IShellService ShellService = Windows.ApplicationModel.DesignMode.DesignModeEnabled + ? null : Ioc.Default.GetRequiredService(); + + private readonly Services.IBluetoothService BluetoothService = Windows.ApplicationModel.DesignMode.DesignModeEnabled + ? null : Ioc.Default.GetRequiredService(); + + public MainPageViewModel() { - this.bleWatcher.Received += async (sender, args) => - { - try - { - if (!args.IsConnectable || control == true) return; - control = true; - var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress); - if (dev.Name == SURFACE_KEYBOARD_NAME && dev.DeviceInformation.Pairing.CanPair) - { - await StaExecuteAsync(() => this.Text = "trying to pair... "); + this.ReloadCommand = new RelayCommand(async () => await ReloadAsync()); - System.Threading.Thread.Sleep(3000); - dev.DeviceInformation.Pairing.Custom.PairingRequested += Custom_PairingRequested; - var t = await dev.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.DisplayPin, DevicePairingProtectionLevel.Encryption); - if (t.Status == DevicePairingResultStatus.Paired) - { - this.bleWatcher.Stop(); - await StaExecuteAsync(() => - { - this.Text = $"Paired and connected {Environment.NewLine} auto closing in 2 seconds "; - CloseApplication(); - } - ); - } - else - await StaExecuteAsync(() => this.Text = t.Status.ToString()); - } - } - catch { } - control = false; - - }; + } @@ -110,22 +82,32 @@ namespace BlueControl.uwp.ViewModels public event PropertyChangedEventHandler PropertyChanged; + public ICommand ReloadCommand { get; private set; } + public async Task ReloadAsync() { this.Text = "Loading..."; - IsConnected = - (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromConnectionStatus(BluetoothConnectionStatus.Connected)) where x.Name == SURFACE_KEYBOARD_NAME select x).Any(); + IsConnected = await BluetoothService.IsConnectedAsync(SURFACE_KEYBOARD_NAME); if (!IsConnected) { - var pairedDevice = - (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)) where x.Name == SURFACE_KEYBOARD_NAME select x).FirstOrDefault(); - if (pairedDevice != null) - await pairedDevice.Pairing.UnpairAsync(); + if (await BluetoothService.IsPairedAsync(SURFACE_KEYBOARD_NAME)) + await BluetoothService.UnpairAsync(SURFACE_KEYBOARD_NAME); this.Text = $"....searching keyboard. {Environment.NewLine} Please confirm is in pairing mode"; - this.bleWatcher.Start(); + await this.BluetoothService.StartAutoPairingAsync( + SURFACE_KEYBOARD_NAME, + () => this.ShellService.UiStaRunAsync(() => this.Text = "trying to pair... ") + , (pin) => this.ShellService.UiStaRunAsync(() => this.Text = $"pin:{Environment.NewLine + pin}") + , () => + ShellService.UiStaRunAsync(() => + { + this.Text = $"Paired and connected {Environment.NewLine} auto closing in 2 seconds "; + CloseApplication(); + }) + , () => ShellService.UiStaRunAsync(() => this.Text = "error trying again") + ); } else {