diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs
index 2b84a3fd..841ece0f 100644
--- a/SafeExamBrowser.Contracts/I18n/TextKey.cs
+++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs
@@ -50,6 +50,9 @@ namespace SafeExamBrowser.Contracts.I18n
SystemControl_BatteryChargeLowInfo,
SystemControl_BatteryRemainingCharge,
SystemControl_KeyboardLayoutTooltip,
+ SystemControl_WirelessConnected,
+ SystemControl_WirelessDisconnected,
+ SystemControl_WirelessNotAvailable,
Version
}
}
diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemWirelessNetworkControl.cs b/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemWirelessNetworkControl.cs
index e6e9ffce..066e9a38 100644
--- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemWirelessNetworkControl.cs
+++ b/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemWirelessNetworkControl.cs
@@ -20,6 +20,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.Taskbar
///
bool HasWirelessNetworkAdapter { set; }
+ ///
+ /// Indicates to the user that a wireless network connection is being established.
+ ///
+ bool IsConnecting { set; }
+
///
/// Sets the current wireless network status.
///
diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml
index cdb789b7..b9461f31 100644
--- a/SafeExamBrowser.Core/I18n/Text.xml
+++ b/SafeExamBrowser.Core/I18n/Text.xml
@@ -35,5 +35,8 @@
The battery charge is getting low. Consider connecting your computer to a power supply in time...
%%HOURS%%h %%MINUTES%%min remaining (%%CHARGE%%%)
Click to choose a different keyboard layout...
+ Connected to '%%NAME%%'
+ Disconnected
+ No wireless network adapter available or turned on
Version
\ No newline at end of file
diff --git a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs
index 343f361a..01882a3e 100644
--- a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs
+++ b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs
@@ -8,7 +8,9 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Timers;
+using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.SystemComponents;
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
@@ -22,14 +24,17 @@ namespace SafeExamBrowser.SystemComponents
{
private const int TWO_SECONDS = 2000;
- private ILogger logger;
private ISystemWirelessNetworkControl control;
+ private ILogger logger;
+ private IList networks = new List();
+ private IText text;
private Timer timer;
private Wifi wifi;
- public WirelessNetwork(ILogger logger)
+ public WirelessNetwork(ILogger logger, IText text)
{
this.logger = logger;
+ this.text = text;
}
public void Initialize(ISystemWirelessNetworkControl control)
@@ -40,6 +45,7 @@ namespace SafeExamBrowser.SystemComponents
if (wifi.NoWifiAvailable || IsTurnedOff())
{
control.HasWirelessNetworkAdapter = false;
+ control.SetTooltip(text.Get(TextKey.SystemControl_WirelessNotAvailable));
logger.Info("Wireless networks cannot be monitored, as there is no hardware adapter available or it is turned off.");
}
else
@@ -72,7 +78,33 @@ namespace SafeExamBrowser.SystemComponents
private void Control_NetworkSelected(IWirelessNetwork network)
{
- throw new NotImplementedException();
+ try
+ {
+ var accessPoint = networks.First(n => n.Id == network.Id).AccessPoint;
+ var authRequest = new AuthRequest(accessPoint);
+
+ accessPoint.ConnectAsync(authRequest, false, (success) => AccessPoint_OnConnectComplete(network.Name, success));
+ control.IsConnecting = true;
+ }
+ catch (Exception e)
+ {
+ logger.Error($"Failed to connect to wireless network '{network.Name}!'", e);
+ }
+ }
+
+ private void AccessPoint_OnConnectComplete(string name, bool success)
+ {
+ if (success)
+ {
+ logger.Info($"Successfully connected to wireless network '{name}'.");
+ }
+ else
+ {
+ logger.Error($"Failed to connect to wireless network '{name}!'");
+ }
+
+ control.IsConnecting = false;
+ UpdateControl();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
@@ -82,7 +114,7 @@ namespace SafeExamBrowser.SystemComponents
private void Wifi_ConnectionStatusChanged(object sender, WifiStatusEventArgs e)
{
- control.NetworkStatus = ToStatus(e.NewStatus);
+ UpdateControl();
}
private bool IsTurnedOff()
@@ -112,32 +144,50 @@ namespace SafeExamBrowser.SystemComponents
private void UpdateControl()
{
- var networks = new List();
-
- control.NetworkStatus = ToStatus(wifi.ConnectionStatus);
-
- try
+ lock (networks)
{
- foreach (var accessPoint in wifi.GetAccessPoints())
+ try
{
- // The user may only connect to an already configured wireless network!
- if (accessPoint.HasProfile)
+ networks.Clear();
+
+ foreach (var accessPoint in wifi.GetAccessPoints())
{
- networks.Add(new WirelessNetworkDefinition
+ // The user may only connect to an already configured wireless network!
+ if (accessPoint.HasProfile)
{
- Name = accessPoint.Name,
- SignalStrength = Convert.ToInt32(accessPoint.SignalStrength),
- Status = accessPoint.IsConnected ? WirelessNetworkStatus.Connected : WirelessNetworkStatus.Disconnected
- });
+ networks.Add(ToDefinition(accessPoint));
+
+ if (accessPoint.IsConnected)
+ {
+ control.SetTooltip(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", accessPoint.Name));
+ }
+ }
}
+
+ if (wifi.ConnectionStatus == WifiStatus.Disconnected)
+ {
+ control.SetTooltip(text.Get(TextKey.SystemControl_WirelessDisconnected));
+ }
+
+ control.NetworkStatus = ToStatus(wifi.ConnectionStatus);
+ control.Update(new List(networks));
+ }
+ catch (Exception e)
+ {
+ logger.Error("Failed to update the wireless network adapter status!", e);
}
}
- catch (Exception e)
- {
- logger.Error("Failed to update the wireless network adapter status!", e);
- }
+ }
- control.Update(networks);
+ private WirelessNetworkDefinition ToDefinition(AccessPoint accessPoint)
+ {
+ return new WirelessNetworkDefinition
+ {
+ AccessPoint = accessPoint,
+ Name = accessPoint.Name,
+ SignalStrength = Convert.ToInt32(accessPoint.SignalStrength),
+ Status = accessPoint.IsConnected ? WirelessNetworkStatus.Connected : WirelessNetworkStatus.Disconnected
+ };
}
private WirelessNetworkStatus ToStatus(WifiStatus status)
diff --git a/SafeExamBrowser.SystemComponents/WirelessNetworkDefinition.cs b/SafeExamBrowser.SystemComponents/WirelessNetworkDefinition.cs
index 93fcc8f4..5a001558 100644
--- a/SafeExamBrowser.SystemComponents/WirelessNetworkDefinition.cs
+++ b/SafeExamBrowser.SystemComponents/WirelessNetworkDefinition.cs
@@ -8,11 +8,14 @@
using System;
using SafeExamBrowser.Contracts.SystemComponents;
+using SimpleWifi;
namespace SafeExamBrowser.SystemComponents
{
internal class WirelessNetworkDefinition : IWirelessNetwork
{
+ internal AccessPoint AccessPoint { get; set; }
+
public Guid Id { get; }
public string Name { get; set; }
public int SignalStrength { get; set; }
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkButton.xaml b/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkButton.xaml
index c7fcd7d3..6e2068bc 100644
--- a/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkButton.xaml
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkButton.xaml
@@ -22,8 +22,8 @@
•
-
-
+
+
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml b/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml
index 2f9be690..aaaff6ef 100644
--- a/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml
@@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Classic.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
@@ -26,7 +27,13 @@
-
+ ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Stretch" Width="40">
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml.cs
index 0d907c85..357fdb8e 100644
--- a/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml.cs
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/WirelessNetworkControl.xaml.cs
@@ -8,10 +8,13 @@
using System;
using System.Collections.Generic;
+using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
+using FontAwesome.WPF;
using SafeExamBrowser.Contracts.SystemComponents;
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
+using SafeExamBrowser.UserInterface.Classic.Utilities;
namespace SafeExamBrowser.UserInterface.Classic.Controls
{
@@ -24,6 +27,20 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
Dispatcher.BeginInvoke(new Action(() =>
{
Button.IsEnabled = value;
+ NoAdapterIcon.Visibility = value ? Visibility.Collapsed : Visibility.Visible;
+ }));
+ }
+ }
+
+ public bool IsConnecting
+ {
+ set
+ {
+ Dispatcher.Invoke(new Action(() =>
+ {
+ LoadingIcon.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
+ SignalStrengthIcon.Visibility = value ? Visibility.Collapsed : Visibility.Visible;
+ NetworkStatusIcon.Visibility = value ? Visibility.Collapsed : Visibility.Visible;
}));
}
}
@@ -34,8 +51,10 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
{
Dispatcher.BeginInvoke(new Action(() =>
{
- NetworkStatusIcon.Text = value == WirelessNetworkStatus.Connected ? "✔" : "❌";
- NetworkStatusIcon.Foreground = value == WirelessNetworkStatus.Connected ? Brushes.Green : Brushes.Red;
+ var icon = value == WirelessNetworkStatus.Connected ? FontAwesomeIcon.Check : FontAwesomeIcon.Close;
+ var brush = value == WirelessNetworkStatus.Connected ? Brushes.Green : Brushes.Orange;
+
+ NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(icon, brush);
}));
}
}
@@ -62,6 +81,8 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
{
Dispatcher.BeginInvoke(new Action(() =>
{
+ NetworksStackPanel.Children.Clear();
+
foreach (var network in networks)
{
var button = new WirelessNetworkButton();
@@ -78,6 +99,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
if (isCurrent)
{
NetworkStatus = network.Status;
+ SignalStrengthIcon.Child = GetIcon(network.SignalStrength);
}
NetworksStackPanel.Children.Add(button);
@@ -89,6 +111,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
{
var originalBrush = Button.Background;
+ SignalStrengthIcon.Child = GetIcon(0);
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver;
Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver;
@@ -105,5 +128,14 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
Button.Background = originalBrush;
};
}
+
+ private UIElement GetIcon(int signalStrength)
+ {
+ var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
+ var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Classic;component/Images/WiFi_{icon}.xaml");
+ var resource = new XamlIconResource(uri);
+
+ return IconResourceLoader.Load(resource);
+ }
}
}
diff --git a/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj b/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj
index aab5737f..68faf27a 100644
--- a/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj
+++ b/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj
@@ -50,6 +50,9 @@
MinimumRecommendedRules.ruleset
+
+ ..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll
+
@@ -255,6 +258,7 @@
ResXFileCodeGenerator
Resources.Designer.cs
+
SettingsSingleFileGenerator
Settings.Designer.cs
diff --git a/SafeExamBrowser.UserInterface.Classic/packages.config b/SafeExamBrowser.UserInterface.Classic/packages.config
new file mode 100644
index 00000000..92648a5c
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Classic/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/SafeExamBrowser/CompositionRoot.cs b/SafeExamBrowser/CompositionRoot.cs
index 3386f9b6..e914c5ae 100644
--- a/SafeExamBrowser/CompositionRoot.cs
+++ b/SafeExamBrowser/CompositionRoot.cs
@@ -82,7 +82,7 @@ namespace SafeExamBrowser
powerSupply = new PowerSupply(new ModuleLogger(logger, typeof(PowerSupply)), text);
processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods);
windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), nativeMethods);
- wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, typeof(WirelessNetwork)));
+ wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, typeof(WirelessNetwork)), text);
runtimeController = new RuntimeController(displayMonitor, new ModuleLogger(logger, typeof(RuntimeController)), processMonitor, Taskbar, windowMonitor);
ShutdownController = new ShutdownController(logger, settings, text, uiFactory);