using Microsoft.WindowsAPICodePack.Net; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Data; using Tango.BL; using Tango.Core; using Tango.Core.Commands; using Tango.Core.Cryptography; using Tango.PPC.Common; using Tango.PPC.Common.Application; using Tango.PPC.Common.Build; using Tango.PPC.Common.Connection; using Tango.PPC.Common.Connectivity; using Tango.PPC.Common.Notifications; using Tango.Settings; using Tango.WiFi; namespace Tango.PPC.UI.Connectivity { public class DefaultConnectivityProvider : ExtendedObject, IConnectivityProvider { private Wifi _wifi; private INotificationProvider _notification; private IMachineProvider _machineProvider; private Rfc2898Cryptographer _cryptographer; private System.Timers.Timer _updateTimer; private System.Timers.Timer _lanUpdateTimer; private WiFiNetwork _connectedNetwork; private PPCSettings _settings; private IBuildProvider _buildProvider; /// /// Occurs when the connectivity provider state has changed (e.g network connected/disconnected). /// public event EventHandler ConnectionStateChanged; private bool _isConnected; /// /// Gets a value indicating whether there is any Internet connection available. /// public bool IsConnected { get { return _buildProvider.IsEureka ? true : _isConnected; } private set { _isConnected = value; RaisePropertyChangedAuto(); } } private bool _isLanConnected; /// /// Gets a value indicating whether there is LAN connection. /// public bool IsLanConnected { get { return _buildProvider.IsEureka ? true : _isLanConnected; } private set { _isLanConnected = value; RaisePropertyChangedAuto(); } } private bool _isHotspoActive; /// /// Gets a value indicating whether the hot spot network is active. /// public bool IsHotspotActive { get { return _isHotspoActive; } set { _isHotspoActive = value; RaisePropertyChangedAuto(); } } /// /// Gets the available WiFi networks. /// public ObservableCollection AvailableWiFiNetworks { get; } /// /// Gets the available WiFi networks as a sorted view source by signal strength. /// public ICollectionView AvailableWiFiNetworksViewSource { get; set; } /// /// Gets the connect to WiFi command. /// public RelayCommand ConnectToWiFiCommand { get; private set; } /// /// Gets the disconnect from WiFi command. /// public RelayCommand DisconnectFromWiFiCommand { get; private set; } /// /// /// public RelayCommand RefreshAvailableWiFiNetworksCommand { get; set; } /// /// Initializes a new instance of the class. /// public DefaultConnectivityProvider(IPPCApplicationManager applicationManager, INotificationProvider notificationProvider, IMachineProvider machineProvider, IBuildProvider buildProvider) { _cryptographer = new Rfc2898Cryptographer(); _buildProvider = buildProvider; _notification = notificationProvider; _machineProvider = machineProvider; AvailableWiFiNetworks = new ObservableCollection(); AvailableWiFiNetworks.EnableCrossThreadOperations(); AvailableWiFiNetworksViewSource = CollectionViewSource.GetDefaultView(AvailableWiFiNetworks); AvailableWiFiNetworksViewSource.SortDescriptions.Add(new SortDescription(nameof(WiFiNetwork.IsConnected), ListSortDirection.Descending)); AvailableWiFiNetworksViewSource.SortDescriptions.Add(new SortDescription(nameof(WiFiNetwork.SignalStrength), ListSortDirection.Descending)); if (!_buildProvider.IsEureka) { _wifi = new Wifi(); applicationManager.ApplicationReady += ApplicationManager_Ready; } ConnectToWiFiCommand = new RelayCommand(async (x) => { await Connect(x); }); DisconnectFromWiFiCommand = new RelayCommand((x) => { Disconnect(x); }); RefreshAvailableWiFiNetworksCommand = new RelayCommand(async () => { await RefreshAvailableWiFiNetworks(); }); _settings = SettingsManager.Default.GetOrCreate(); } /// /// Handles the application manager ApplicationReady event. /// /// /// private void ApplicationManager_Ready(object sender, EventArgs e) { Task.Factory.StartNew(async () => { Thread.Sleep(2000); await RefreshAvailableWiFiNetworks(); var settings = SettingsManager.Default.GetOrCreate(); var networks = AvailableWiFiNetworks.ToList(); var auto_connect_network = networks.FirstOrDefault(x => x.Name == settings.AutoConnectWiFiName); IsConnected = networks.Exists(x => x.IsConnected); if (IsConnected) { _connectedNetwork = auto_connect_network; } if (auto_connect_network != null && !auto_connect_network.IsConnected) { auto_connect_network.AutoConnect = true; await Connect(auto_connect_network, _cryptographer.Decrypt(settings.AutoConnectWiFiPassword)); } }); _updateTimer = new System.Timers.Timer(TimeSpan.FromSeconds(30).TotalMilliseconds); _updateTimer.Elapsed += _updateTimer_Elapsed; _updateTimer.Start(); _lanUpdateTimer = new System.Timers.Timer(TimeSpan.FromSeconds(10).TotalMilliseconds); _lanUpdateTimer.Elapsed += _lanUpdateTimer_Elapsed; _lanUpdateTimer.Start(); } private void _lanUpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { foreach (NetworkInterface net in NetworkInterface.GetAllNetworkInterfaces()) { if ((net.NetworkInterfaceType == NetworkInterfaceType.Ethernet || net.NetworkInterfaceType == NetworkInterfaceType.Ethernet3Megabit || net.NetworkInterfaceType == NetworkInterfaceType.FastEthernetFx || net.NetworkInterfaceType == NetworkInterfaceType.FastEthernetT || net.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet) && net.Name.ToStringOrEmpty().StartsWith("Ethernet") && net.OperationalStatus == OperationalStatus.Up) { IsLanConnected = true; return; } } IsLanConnected = false; } /// /// Periodically checks if WiFI network is gone/disconnected. /// /// The source of the event. /// The instance containing the event data. private void _updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (IsConnected && _connectedNetwork != null) { var networks = GetAvailableWiFiNetworks().Result; var matching_network = networks.FirstOrDefault(x => x.Name == _connectedNetwork.Name); if (matching_network == null || !matching_network.AccessPoint.IsConnected) { OnConnectionStateChanged(false); } } } /// /// Gets the available WiFi networks. /// /// public Task> GetAvailableWiFiNetworks() { return Task.Factory.StartNew>(() => { var accessPoints = _wifi.GetAccessPoints(); AvailableWiFiNetworks.Where(x => !accessPoints.ToList().Exists(y => y.Name == x.Name)).ToList().ForEach(x => AvailableWiFiNetworks.Remove(x)); foreach (var ap in accessPoints.ToList()) { var network = AvailableWiFiNetworks.FirstOrDefault(x => x.Name == ap.Name); if (network == null) { network = new WiFiNetwork(ap, _wifi); AvailableWiFiNetworks.Add(network); } else { network.AccessPoint = ap; } } return AvailableWiFiNetworks.ToList(); }); } /// /// Resets the available WiFi networks collection. /// public Task RefreshAvailableWiFiNetworks() { return Task.Factory.StartNew(() => { AvailableWiFiNetworks.Clear(); if (!_buildProvider.IsEureka) { GetAvailableWiFiNetworks().Wait(); } }); } /// /// Checks the Internet connection. /// /// public Task CheckInternetConnection() { if (_settings.BypassInternetConnectivityCheck) { return Task.FromResult(true); } return Task.Factory.StartNew(() => { try { return NetworkListManager.GetNetworks(NetworkConnectivityLevels.Connected).Any(x => x.IsConnectedToInternet); } catch { return true; } }); } /// /// Connects the specified network. /// /// The network. /// public async Task Connect(WiFiNetwork network, String password = null) { var auth = network.CreateAuthenticationRequest(); bool result = false; if (password == null) { if ((auth.IsPasswordRequired || auth.IsUserNameRequired) && !network.HasProfile) { var vm = await _notification.ShowDialog(new WiFiAuthenticationViewVM(auth, network)); if (vm.DialogResult) { result = await network.Connect(auth, true); if (!result) { await _notification.ShowError("Could not connect to the specified network. Please check your password."); await network.Forget(); } await RefreshAvailableWiFiNetworks(); } else { return false; } } else { result = await network.Connect(auth, false); await RefreshAvailableWiFiNetworks(); } } else { auth.Password = password; result = await network.Connect(auth, true); await RefreshAvailableWiFiNetworks(); } if (result) { OnConnectionStateChanged(true); var settings = SettingsManager.Default.GetOrCreate(); settings.AutoConnectWiFiName = network.AutoConnect ? network.Name : null; settings.AutoConnectWiFiPassword = _cryptographer.Encrypt(auth.Password); settings.Save(); _connectedNetwork = network; } return result; } /// /// Disconnects the specified network. /// /// The network. /// public void Disconnect(WiFiNetwork network) { Task.Factory.StartNew(() => { var settings = SettingsManager.Default.GetOrCreate(); settings.AutoConnectWiFiName = null; settings.AutoConnectWiFiPassword = null; settings.Save(); network.AutoConnect = false; network.Disconnect().Wait(); RefreshAvailableWiFiNetworks().Wait(); OnConnectionStateChanged(false); }); } /// /// Called when the connection state has been changed /// /// if set to true [connected]. protected virtual void OnConnectionStateChanged(bool connected) { if (!connected) { _connectedNetwork = null; } IsConnected = connected; ConnectionStateChanged?.Invoke(this, new ConnectionStateEventArgs() { IsConnected = connected }); } } }