SEBWIN-110: Implemented basic version of wireless network system control.

This commit is contained in:
dbuechel 2017-11-14 15:43:13 +01:00
parent 00754ee100
commit 5b46dc1258
11 changed files with 140 additions and 29 deletions

View file

@ -50,6 +50,9 @@ namespace SafeExamBrowser.Contracts.I18n
SystemControl_BatteryChargeLowInfo,
SystemControl_BatteryRemainingCharge,
SystemControl_KeyboardLayoutTooltip,
SystemControl_WirelessConnected,
SystemControl_WirelessDisconnected,
SystemControl_WirelessNotAvailable,
Version
}
}

View file

@ -20,6 +20,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.Taskbar
/// </summary>
bool HasWirelessNetworkAdapter { set; }
/// <summary>
/// Indicates to the user that a wireless network connection is being established.
/// </summary>
bool IsConnecting { set; }
/// <summary>
/// Sets the current wireless network status.
/// </summary>

View file

@ -35,5 +35,8 @@
<SystemControl_BatteryChargeLowInfo>The battery charge is getting low. Consider connecting your computer to a power supply in time...</SystemControl_BatteryChargeLowInfo>
<SystemControl_BatteryRemainingCharge>%%HOURS%%h %%MINUTES%%min remaining (%%CHARGE%%%)</SystemControl_BatteryRemainingCharge>
<SystemControl_KeyboardLayoutTooltip>Click to choose a different keyboard layout...</SystemControl_KeyboardLayoutTooltip>
<SystemControl_WirelessConnected>Connected to '%%NAME%%'</SystemControl_WirelessConnected>
<SystemControl_WirelessDisconnected>Disconnected</SystemControl_WirelessDisconnected>
<SystemControl_WirelessNotAvailable>No wireless network adapter available or turned on</SystemControl_WirelessNotAvailable>
<Version>Version</Version>
</Text>

View file

@ -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<WirelessNetworkDefinition> networks = new List<WirelessNetworkDefinition>();
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<IWirelessNetwork>();
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<IWirelessNetwork>(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)

View file

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

View file

@ -22,8 +22,8 @@
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
<TextBlock x:Name="SignalStrengthTextBlock" Grid.Column="1" FontWeight="Bold" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
<TextBlock x:Name="NetworkNameTextBlock" Grid.Column="2" Foreground="Gray" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
<TextBlock x:Name="SignalStrengthTextBlock" Grid.Column="1" Foreground="Gray" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
<TextBlock x:Name="NetworkNameTextBlock" Grid.Column="2" FontWeight="Bold" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
</Grid>
</Button>
</Grid>

View file

@ -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 @@
</Border>
</Popup>
<Button x:Name="Button" Background="Transparent" HorizontalContentAlignment="Stretch" Template="{StaticResource TaskbarButton}"
ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Stretch" Width="40" />
<TextBlock x:Name="NetworkStatusIcon" HorizontalAlignment="Right" Padding="6,2" Panel.ZIndex="10" VerticalAlignment="Bottom" />
ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Stretch" Width="40">
<Grid>
<Viewbox x:Name="SignalStrengthIcon" Stretch="Uniform" Width="Auto" />
<fa:ImageAwesome x:Name="NoAdapterIcon" Foreground="Red" Icon="Ban" Margin="1" Opacity="0.2" Visibility="Collapsed" />
<fa:ImageAwesome x:Name="LoadingIcon" Foreground="Gray" Icon="Cog" Margin="5" Spin="True" SpinDuration="2" Visibility="Collapsed" />
<Image x:Name="NetworkStatusIcon" Height="10" HorizontalAlignment="Right" Margin="0,2" Panel.ZIndex="10" VerticalAlignment="Bottom" />
</Grid>
</Button>
</Grid>
</UserControl>

View file

@ -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 ? "&#10004;" : "&#10060;";
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);
}
}
}

View file

@ -50,6 +50,9 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
<HintPath>..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Windows.Forms" />
@ -255,6 +258,7 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net452" />
</packages>

View file

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