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 });
}
}
}