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_BatteryChargeLowInfo,
SystemControl_BatteryRemainingCharge, SystemControl_BatteryRemainingCharge,
SystemControl_KeyboardLayoutTooltip, SystemControl_KeyboardLayoutTooltip,
SystemControl_WirelessConnected,
SystemControl_WirelessDisconnected,
SystemControl_WirelessNotAvailable,
Version Version
} }
} }

View file

@ -20,6 +20,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.Taskbar
/// </summary> /// </summary>
bool HasWirelessNetworkAdapter { set; } bool HasWirelessNetworkAdapter { set; }
/// <summary>
/// Indicates to the user that a wireless network connection is being established.
/// </summary>
bool IsConnecting { set; }
/// <summary> /// <summary>
/// Sets the current wireless network status. /// Sets the current wireless network status.
/// </summary> /// </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_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_BatteryRemainingCharge>%%HOURS%%h %%MINUTES%%min remaining (%%CHARGE%%%)</SystemControl_BatteryRemainingCharge>
<SystemControl_KeyboardLayoutTooltip>Click to choose a different keyboard layout...</SystemControl_KeyboardLayoutTooltip> <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> <Version>Version</Version>
</Text> </Text>

View file

@ -8,7 +8,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Timers; using System.Timers;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.SystemComponents;
using SafeExamBrowser.Contracts.UserInterface.Taskbar; using SafeExamBrowser.Contracts.UserInterface.Taskbar;
@ -22,14 +24,17 @@ namespace SafeExamBrowser.SystemComponents
{ {
private const int TWO_SECONDS = 2000; private const int TWO_SECONDS = 2000;
private ILogger logger;
private ISystemWirelessNetworkControl control; private ISystemWirelessNetworkControl control;
private ILogger logger;
private IList<WirelessNetworkDefinition> networks = new List<WirelessNetworkDefinition>();
private IText text;
private Timer timer; private Timer timer;
private Wifi wifi; private Wifi wifi;
public WirelessNetwork(ILogger logger) public WirelessNetwork(ILogger logger, IText text)
{ {
this.logger = logger; this.logger = logger;
this.text = text;
} }
public void Initialize(ISystemWirelessNetworkControl control) public void Initialize(ISystemWirelessNetworkControl control)
@ -40,6 +45,7 @@ namespace SafeExamBrowser.SystemComponents
if (wifi.NoWifiAvailable || IsTurnedOff()) if (wifi.NoWifiAvailable || IsTurnedOff())
{ {
control.HasWirelessNetworkAdapter = false; 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."); logger.Info("Wireless networks cannot be monitored, as there is no hardware adapter available or it is turned off.");
} }
else else
@ -72,7 +78,33 @@ namespace SafeExamBrowser.SystemComponents
private void Control_NetworkSelected(IWirelessNetwork network) 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) private void Timer_Elapsed(object sender, ElapsedEventArgs e)
@ -82,7 +114,7 @@ namespace SafeExamBrowser.SystemComponents
private void Wifi_ConnectionStatusChanged(object sender, WifiStatusEventArgs e) private void Wifi_ConnectionStatusChanged(object sender, WifiStatusEventArgs e)
{ {
control.NetworkStatus = ToStatus(e.NewStatus); UpdateControl();
} }
private bool IsTurnedOff() private bool IsTurnedOff()
@ -112,32 +144,50 @@ namespace SafeExamBrowser.SystemComponents
private void UpdateControl() private void UpdateControl()
{ {
var networks = new List<IWirelessNetwork>(); lock (networks)
control.NetworkStatus = ToStatus(wifi.ConnectionStatus);
try
{ {
foreach (var accessPoint in wifi.GetAccessPoints()) try
{ {
// The user may only connect to an already configured wireless network! networks.Clear();
if (accessPoint.HasProfile)
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, networks.Add(ToDefinition(accessPoint));
SignalStrength = Convert.ToInt32(accessPoint.SignalStrength),
Status = accessPoint.IsConnected ? WirelessNetworkStatus.Connected : WirelessNetworkStatus.Disconnected 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) private WirelessNetworkStatus ToStatus(WifiStatus status)

View file

@ -8,11 +8,14 @@
using System; using System;
using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.SystemComponents;
using SimpleWifi;
namespace SafeExamBrowser.SystemComponents namespace SafeExamBrowser.SystemComponents
{ {
internal class WirelessNetworkDefinition : IWirelessNetwork internal class WirelessNetworkDefinition : IWirelessNetwork
{ {
internal AccessPoint AccessPoint { get; set; }
public Guid Id { get; } public Guid Id { get; }
public string Name { get; set; } public string Name { get; set; }
public int SignalStrength { get; set; } public int SignalStrength { get; set; }

View file

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

View file

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Classic.Controls" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Classic.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40"> mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
@ -26,7 +27,13 @@
</Border> </Border>
</Popup> </Popup>
<Button x:Name="Button" Background="Transparent" HorizontalContentAlignment="Stretch" Template="{StaticResource TaskbarButton}" <Button x:Name="Button" Background="Transparent" HorizontalContentAlignment="Stretch" Template="{StaticResource TaskbarButton}"
ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Stretch" Width="40" /> ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Stretch" Width="40">
<TextBlock x:Name="NetworkStatusIcon" HorizontalAlignment="Right" Padding="6,2" Panel.ZIndex="10" VerticalAlignment="Bottom" /> <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> </Grid>
</UserControl> </UserControl>

View file

@ -8,10 +8,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using FontAwesome.WPF;
using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.SystemComponents;
using SafeExamBrowser.Contracts.UserInterface.Taskbar; using SafeExamBrowser.Contracts.UserInterface.Taskbar;
using SafeExamBrowser.UserInterface.Classic.Utilities;
namespace SafeExamBrowser.UserInterface.Classic.Controls namespace SafeExamBrowser.UserInterface.Classic.Controls
{ {
@ -24,6 +27,20 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
Dispatcher.BeginInvoke(new Action(() => Dispatcher.BeginInvoke(new Action(() =>
{ {
Button.IsEnabled = value; 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(() => Dispatcher.BeginInvoke(new Action(() =>
{ {
NetworkStatusIcon.Text = value == WirelessNetworkStatus.Connected ? "&#10004;" : "&#10060;"; var icon = value == WirelessNetworkStatus.Connected ? FontAwesomeIcon.Check : FontAwesomeIcon.Close;
NetworkStatusIcon.Foreground = value == WirelessNetworkStatus.Connected ? Brushes.Green : Brushes.Red; 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(() => Dispatcher.BeginInvoke(new Action(() =>
{ {
NetworksStackPanel.Children.Clear();
foreach (var network in networks) foreach (var network in networks)
{ {
var button = new WirelessNetworkButton(); var button = new WirelessNetworkButton();
@ -78,6 +99,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
if (isCurrent) if (isCurrent)
{ {
NetworkStatus = network.Status; NetworkStatus = network.Status;
SignalStrengthIcon.Child = GetIcon(network.SignalStrength);
} }
NetworksStackPanel.Children.Add(button); NetworksStackPanel.Children.Add(button);
@ -89,6 +111,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
{ {
var originalBrush = Button.Background; var originalBrush = Button.Background;
SignalStrengthIcon.Child = GetIcon(0);
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver; Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver;
Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver; Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver;
@ -105,5 +128,14 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
Button.Background = originalBrush; 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> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <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="System" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
@ -255,6 +258,7 @@
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <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); powerSupply = new PowerSupply(new ModuleLogger(logger, typeof(PowerSupply)), text);
processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods); processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods);
windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), 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); runtimeController = new RuntimeController(displayMonitor, new ModuleLogger(logger, typeof(RuntimeController)), processMonitor, Taskbar, windowMonitor);
ShutdownController = new ShutdownController(logger, settings, text, uiFactory); ShutdownController = new ShutdownController(logger, settings, text, uiFactory);