diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs index ce228961..b6983d05 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs @@ -18,8 +18,8 @@ using SafeExamBrowser.Settings.Applications; using SafeExamBrowser.SystemComponents.Contracts; using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -41,7 +41,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations private Mock taskview; private Mock text; private Mock uiFactory; - private Mock wirelessAdapter; + private Mock networkAdapter; private ShellOperation sut; @@ -55,13 +55,13 @@ namespace SafeExamBrowser.Client.UnitTests.Operations aboutNotification = new Mock(); keyboard = new Mock(); logNotification = new Mock(); + networkAdapter = new Mock(); powerSupply = new Mock(); systemInfo = new Mock(); taskbar = new Mock(); taskview = new Mock(); text = new Mock(); uiFactory = new Mock(); - wirelessAdapter = new Mock(); context.Settings = new AppSettings(); @@ -77,13 +77,13 @@ namespace SafeExamBrowser.Client.UnitTests.Operations keyboard.Object, logger.Object, logNotification.Object, + networkAdapter.Object, powerSupply.Object, systemInfo.Object, taskbar.Object, taskview.Object, text.Object, - uiFactory.Object, - wirelessAdapter.Object); + uiFactory.Object); } [TestMethod] @@ -99,7 +99,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations context.Settings.ActionCenter.EnableActionCenter = true; context.Settings.Keyboard.AllowAltTab = true; context.Settings.Security.AllowTermination = true; - + sut.Perform(); actionCenter.Verify(a => a.Register(It.Is(a2 => a2 == actionCenterActivator.Object)), Times.Once); @@ -281,23 +281,23 @@ namespace SafeExamBrowser.Client.UnitTests.Operations context.Settings.ActionCenter.EnableActionCenter = true; context.Settings.ActionCenter.ShowAudio = true; context.Settings.ActionCenter.ShowKeyboardLayout = true; - context.Settings.ActionCenter.ShowWirelessNetwork = true; + context.Settings.ActionCenter.ShowNetwork = true; context.Settings.Taskbar.EnableTaskbar = true; context.Settings.Taskbar.ShowAudio = true; context.Settings.Taskbar.ShowKeyboardLayout = true; - context.Settings.Taskbar.ShowWirelessNetwork = true; + context.Settings.Taskbar.ShowNetwork = true; systemInfo.SetupGet(s => s.HasBattery).Returns(true); uiFactory.Setup(f => f.CreateAudioControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreatePowerSupplyControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); - uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); + uiFactory.Setup(f => f.CreateNetworkControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); sut.Perform(); audio.Verify(a => a.Initialize(), Times.Once); powerSupply.Verify(p => p.Initialize(), Times.Once); - wirelessAdapter.Verify(w => w.Initialize(), Times.Once); + networkAdapter.Verify(w => w.Initialize(), Times.Once); keyboard.Verify(k => k.Initialize(), Times.Once); actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Exactly(4)); taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Exactly(4)); @@ -309,23 +309,23 @@ namespace SafeExamBrowser.Client.UnitTests.Operations context.Settings.ActionCenter.EnableActionCenter = true; context.Settings.ActionCenter.ShowAudio = false; context.Settings.ActionCenter.ShowKeyboardLayout = false; - context.Settings.ActionCenter.ShowWirelessNetwork = false; + context.Settings.ActionCenter.ShowNetwork = false; context.Settings.Taskbar.EnableTaskbar = true; context.Settings.Taskbar.ShowAudio = false; context.Settings.Taskbar.ShowKeyboardLayout = false; - context.Settings.Taskbar.ShowWirelessNetwork = false; + context.Settings.Taskbar.ShowNetwork = false; systemInfo.SetupGet(s => s.HasBattery).Returns(false); uiFactory.Setup(f => f.CreateAudioControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreatePowerSupplyControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); - uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); + uiFactory.Setup(f => f.CreateNetworkControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); sut.Perform(); audio.Verify(a => a.Initialize(), Times.Once); powerSupply.Verify(p => p.Initialize(), Times.Once); - wirelessAdapter.Verify(w => w.Initialize(), Times.Once); + networkAdapter.Verify(w => w.Initialize(), Times.Once); keyboard.Verify(k => k.Initialize(), Times.Once); actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Never); taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Never); @@ -408,7 +408,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations logNotification.Verify(c => c.Terminate(), Times.Once); powerSupply.Verify(p => p.Terminate(), Times.Once); keyboard.Verify(k => k.Terminate(), Times.Once); - wirelessAdapter.Verify(w => w.Terminate(), Times.Once); + networkAdapter.Verify(w => w.Terminate(), Times.Once); } } } diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 0669473e..86902dba 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -38,11 +38,11 @@ using SafeExamBrowser.Settings.UserInterface; using SafeExamBrowser.SystemComponents; using SafeExamBrowser.SystemComponents.Audio; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using SafeExamBrowser.SystemComponents.Keyboard; +using SafeExamBrowser.SystemComponents.Network; using SafeExamBrowser.SystemComponents.PowerSupply; -using SafeExamBrowser.SystemComponents.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.MessageBox; @@ -71,6 +71,7 @@ namespace SafeExamBrowser.Client private ILogger logger; private IMessageBox messageBox; private INativeMethods nativeMethods; + private INetworkAdapter networkAdapter; private IPowerSupply powerSupply; private IRuntimeProxy runtimeProxy; private ISystemInfo systemInfo; @@ -79,7 +80,6 @@ namespace SafeExamBrowser.Client private IUserInfo userInfo; private IText text; private IUserInterfaceFactory uiFactory; - private IWirelessAdapter wirelessAdapter; internal ClientController ClientController { get; private set; } @@ -96,13 +96,13 @@ namespace SafeExamBrowser.Client context = new ClientContext(); messageBox = BuildMessageBox(); nativeMethods = new NativeMethods(); + networkAdapter = new NetworkAdapter(ModuleLogger(nameof(NetworkAdapter)), nativeMethods); powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply))); runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client); systemInfo = new SystemInfo(); taskbar = uiFactory.CreateTaskbar(ModuleLogger("Taskbar")); taskview = uiFactory.CreateTaskview(); userInfo = new UserInfo(ModuleLogger(nameof(UserInfo))); - wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter))); var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory))); var applicationMonitor = new ApplicationMonitor(TWO_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, processFactory); @@ -157,13 +157,13 @@ namespace SafeExamBrowser.Client internal void LogStartupInformation() { - logger.Log($"# New client instance started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); + logger.Log($"# New client instance started at {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}"); logger.Log(string.Empty); } internal void LogShutdownInformation() { - logger?.Log($"# Client instance terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); + logger?.Log($"# Client instance terminated at {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}"); } private void ValidateCommandLineArguments() @@ -271,7 +271,7 @@ namespace SafeExamBrowser.Client private IOperation BuildServerOperation() { - var server = new ServerProxy(context.AppConfig, ModuleLogger(nameof(ServerProxy)), systemInfo, userInfo, powerSupply, wirelessAdapter); + var server = new ServerProxy(context.AppConfig, ModuleLogger(nameof(ServerProxy)), systemInfo, userInfo, powerSupply, networkAdapter); var operation = new ServerOperation(context, logger, server); context.Server = server; @@ -293,13 +293,13 @@ namespace SafeExamBrowser.Client keyboard, logger, logNotification, + networkAdapter, powerSupply, systemInfo, taskbar, taskview, text, - uiFactory, - wirelessAdapter); + uiFactory); context.Activators.Add(new ActionCenterKeyboardActivator(ModuleLogger(nameof(ActionCenterKeyboardActivator)), nativeMethods)); context.Activators.Add(new ActionCenterTouchActivator(ModuleLogger(nameof(ActionCenterTouchActivator)), nativeMethods)); diff --git a/SafeExamBrowser.Client/Operations/ShellOperation.cs b/SafeExamBrowser.Client/Operations/ShellOperation.cs index 7be57a74..c548b618 100644 --- a/SafeExamBrowser.Client/Operations/ShellOperation.cs +++ b/SafeExamBrowser.Client/Operations/ShellOperation.cs @@ -15,8 +15,8 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -24,19 +24,19 @@ namespace SafeExamBrowser.Client.Operations { internal class ShellOperation : ClientOperation { - private IActionCenter actionCenter; - private IAudio audio; - private INotification aboutNotification; - private IKeyboard keyboard; - private ILogger logger; - private INotification logNotification; - private IPowerSupply powerSupply; - private ISystemInfo systemInfo; - private ITaskbar taskbar; - private ITaskview taskview; - private IText text; - private IUserInterfaceFactory uiFactory; - private IWirelessAdapter wirelessAdapter; + private readonly IActionCenter actionCenter; + private readonly IAudio audio; + private readonly INotification aboutNotification; + private readonly IKeyboard keyboard; + private readonly ILogger logger; + private readonly INotification logNotification; + private readonly INetworkAdapter networkAdapter; + private readonly IPowerSupply powerSupply; + private readonly ISystemInfo systemInfo; + private readonly ITaskbar taskbar; + private readonly ITaskview taskview; + private readonly IText text; + private readonly IUserInterfaceFactory uiFactory; public override event ActionRequiredEventHandler ActionRequired { add { } remove { } } public override event StatusChangedEventHandler StatusChanged; @@ -49,13 +49,13 @@ namespace SafeExamBrowser.Client.Operations IKeyboard keyboard, ILogger logger, INotification logNotification, + INetworkAdapter networkAdapter, IPowerSupply powerSupply, ISystemInfo systemInfo, ITaskbar taskbar, ITaskview taskview, IText text, - IUserInterfaceFactory uiFactory, - IWirelessAdapter wirelessAdapter) : base(context) + IUserInterfaceFactory uiFactory) : base(context) { this.aboutNotification = aboutNotification; this.actionCenter = actionCenter; @@ -63,13 +63,13 @@ namespace SafeExamBrowser.Client.Operations this.keyboard = keyboard; this.logger = logger; this.logNotification = logNotification; + this.networkAdapter = networkAdapter; this.powerSupply = powerSupply; this.systemInfo = systemInfo; this.text = text; this.taskbar = taskbar; this.taskview = taskview; this.uiFactory = uiFactory; - this.wirelessAdapter = wirelessAdapter; } public override OperationResult Perform() @@ -134,7 +134,7 @@ namespace SafeExamBrowser.Client.Operations InitializeClockForActionCenter(); InitializeLogNotificationForActionCenter(); InitializeKeyboardLayoutForActionCenter(); - InitializeWirelessNetworkForActionCenter(); + InitializeNetworkForActionCenter(); InitializePowerSupplyForActionCenter(); InitializeQuitButtonForActionCenter(); } @@ -155,7 +155,7 @@ namespace SafeExamBrowser.Client.Operations InitializeAboutNotificationForTaskbar(); InitializeLogNotificationForTaskbar(); InitializePowerSupplyForTaskbar(); - InitializeWirelessNetworkForTaskbar(); + InitializeNetworkForTaskbar(); InitializeAudioForTaskbar(); InitializeKeyboardLayoutForTaskbar(); InitializeClockForTaskbar(); @@ -204,8 +204,8 @@ namespace SafeExamBrowser.Client.Operations { audio.Initialize(); keyboard.Initialize(); + networkAdapter.Initialize(); powerSupply.Initialize(); - wirelessAdapter.Initialize(); } private void InitializeAboutNotificationForActionCenter() @@ -308,19 +308,19 @@ namespace SafeExamBrowser.Client.Operations taskbar.ShowQuitButton = Context.Settings.Security.AllowTermination; } - private void InitializeWirelessNetworkForActionCenter() + private void InitializeNetworkForActionCenter() { - if (Context.Settings.ActionCenter.ShowWirelessNetwork) + if (Context.Settings.ActionCenter.ShowNetwork) { - actionCenter.AddSystemControl(uiFactory.CreateWirelessNetworkControl(wirelessAdapter, Location.ActionCenter)); + actionCenter.AddSystemControl(uiFactory.CreateNetworkControl(networkAdapter, Location.ActionCenter)); } } - private void InitializeWirelessNetworkForTaskbar() + private void InitializeNetworkForTaskbar() { - if (Context.Settings.Taskbar.ShowWirelessNetwork) + if (Context.Settings.Taskbar.ShowNetwork) { - taskbar.AddSystemControl(uiFactory.CreateWirelessNetworkControl(wirelessAdapter, Location.Taskbar)); + taskbar.AddSystemControl(uiFactory.CreateNetworkControl(networkAdapter, Location.Taskbar)); } } @@ -342,8 +342,8 @@ namespace SafeExamBrowser.Client.Operations { audio.Terminate(); keyboard.Terminate(); + networkAdapter.Terminate(); powerSupply.Terminate(); - wirelessAdapter.Terminate(); } } } diff --git a/SafeExamBrowser.Configuration.UnitTests/ConfigurationRepositoryTests.cs b/SafeExamBrowser.Configuration.UnitTests/ConfigurationRepositoryTests.cs index 4719bd50..fbab2226 100644 --- a/SafeExamBrowser.Configuration.UnitTests/ConfigurationRepositoryTests.cs +++ b/SafeExamBrowser.Configuration.UnitTests/ConfigurationRepositoryTests.cs @@ -30,7 +30,6 @@ namespace SafeExamBrowser.Configuration.UnitTests private Mock certificateStore; private Mock fileLoader; private Mock fileSaver; - private Mock hashAlgorithm; private Mock logger; private Mock networkLoader; private Mock xmlParser; @@ -44,7 +43,6 @@ namespace SafeExamBrowser.Configuration.UnitTests certificateStore = new Mock(); fileLoader = new Mock(); fileSaver = new Mock(); - hashAlgorithm = new Mock(); logger = new Mock(); networkLoader = new Mock(); xmlParser = new Mock(); @@ -56,7 +54,7 @@ namespace SafeExamBrowser.Configuration.UnitTests SetEntryAssembly(); - sut = new ConfigurationRepository(certificateStore.Object, hashAlgorithm.Object, logger.Object); + sut = new ConfigurationRepository(certificateStore.Object, logger.Object); sut.InitializeAppConfig(); } diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs index f9418a1b..dde5c17b 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs @@ -29,8 +29,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping case Keys.UserInterface.ShowKeyboardLayout: MapShowKeyboardLayout(settings, value); break; - case Keys.UserInterface.ShowWirelessNetwork: - MapShowWirelessNetwork(settings, value); + case Keys.UserInterface.ShowNetwork: + MapShowNetwork(settings, value); break; case Keys.UserInterface.Taskbar.EnableTaskbar: MapEnableTaskbar(settings, value); @@ -79,12 +79,12 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping } } - private void MapShowWirelessNetwork(AppSettings settings, object value) + private void MapShowNetwork(AppSettings settings, object value) { if (value is bool show) { - settings.ActionCenter.ShowWirelessNetwork = show; - settings.Taskbar.ShowWirelessNetwork = show; + settings.ActionCenter.ShowNetwork = show; + settings.Taskbar.ShowNetwork = show; } } diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs index 8b43a32c..d4e54379 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs @@ -101,9 +101,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData settings.ActionCenter.EnableActionCenter = true; settings.ActionCenter.ShowApplicationInfo = true; settings.ActionCenter.ShowApplicationLog = false; - settings.ActionCenter.ShowKeyboardLayout = true; - settings.ActionCenter.ShowWirelessNetwork = false; settings.ActionCenter.ShowClock = true; + settings.ActionCenter.ShowKeyboardLayout = true; + settings.ActionCenter.ShowNetwork = false; settings.Applications.Blacklist.Add(new BlacklistApplication { ExecutableName = "AA_v3.exe", OriginalName = "AA_v3.exe" }); settings.Applications.Blacklist.Add(new BlacklistApplication { ExecutableName = "AeroAdmin.exe", OriginalName = "AeroAdmin.exe" }); @@ -283,12 +283,12 @@ namespace SafeExamBrowser.Configuration.ConfigurationData settings.Taskbar.EnableTaskbar = true; settings.Taskbar.ShowApplicationInfo = false; settings.Taskbar.ShowApplicationLog = false; - settings.Taskbar.ShowKeyboardLayout = true; - settings.Taskbar.ShowWirelessNetwork = false; settings.Taskbar.ShowClock = true; + settings.Taskbar.ShowKeyboardLayout = true; + settings.Taskbar.ShowNetwork = false; settings.UserInterfaceMode = UserInterfaceMode.Desktop; - + return settings; } } diff --git a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs index a6cb7390..1ed68e0c 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs @@ -327,7 +327,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData internal const string ShowAudio = "audioControlEnabled"; internal const string ShowClock = "showTime"; internal const string ShowKeyboardLayout = "showInputLanguage"; - internal const string ShowWirelessNetwork = "allowWlan"; + internal const string ShowNetwork = "allowWlan"; internal const string UserInterfaceMode = "touchOptimized"; internal static class ActionCenter diff --git a/SafeExamBrowser.Configuration/ConfigurationRepository.cs b/SafeExamBrowser.Configuration/ConfigurationRepository.cs index 718315d2..9fdf21af 100644 --- a/SafeExamBrowser.Configuration/ConfigurationRepository.cs +++ b/SafeExamBrowser.Configuration/ConfigurationRepository.cs @@ -22,21 +22,19 @@ namespace SafeExamBrowser.Configuration { public class ConfigurationRepository : IConfigurationRepository { - private ICertificateStore certificateStore; - private IList dataParsers; - private IList dataSerializers; - private DataMapper dataMapper; - private DataProcessor dataProcessor; - private DataValues dataValues; - private IHashAlgorithm hashAlgorithm; - private ILogger logger; - private IList resourceLoaders; - private IList resourceSavers; + private readonly ICertificateStore certificateStore; + private readonly IList dataParsers; + private readonly IList dataSerializers; + private readonly DataMapper dataMapper; + private readonly DataProcessor dataProcessor; + private readonly DataValues dataValues; + private readonly ILogger logger; + private readonly IList resourceLoaders; + private readonly IList resourceSavers; - public ConfigurationRepository(ICertificateStore certificateStore, IHashAlgorithm hashAlgorithm, IModuleLogger logger) + public ConfigurationRepository(ICertificateStore certificateStore, IModuleLogger logger) { this.certificateStore = certificateStore; - this.hashAlgorithm = hashAlgorithm; this.logger = logger; dataParsers = new List(); @@ -171,7 +169,7 @@ namespace SafeExamBrowser.Configuration var status = LoadStatus.NotSupported; var resourceLoader = resourceLoaders.FirstOrDefault(l => l.CanLoad(resource)); - data = default(Stream); + data = default; if (resourceLoader != null) { @@ -191,8 +189,8 @@ namespace SafeExamBrowser.Configuration var parser = dataParsers.FirstOrDefault(p => p.CanParse(data)); var status = LoadStatus.NotSupported; - encryption = default(EncryptionParameters); - format = default(FormatType); + encryption = default; + format = default; rawData = default(Dictionary); if (parser != null) @@ -237,7 +235,7 @@ namespace SafeExamBrowser.Configuration var serializer = dataSerializers.FirstOrDefault(s => s.CanSerialize(format)); var status = SaveStatus.NotSupported; - serialized = default(Stream); + serialized = default; if (serializer != null) { diff --git a/SafeExamBrowser.I18n.Contracts/TextKey.cs b/SafeExamBrowser.I18n.Contracts/TextKey.cs index caa74a9f..5c9271d0 100644 --- a/SafeExamBrowser.I18n.Contracts/TextKey.cs +++ b/SafeExamBrowser.I18n.Contracts/TextKey.cs @@ -213,10 +213,11 @@ namespace SafeExamBrowser.I18n.Contracts SystemControl_BatteryChargeLowInfo, SystemControl_BatteryRemainingCharge, SystemControl_KeyboardLayoutTooltip, - SystemControl_WirelessConnected, - SystemControl_WirelessConnecting, - SystemControl_WirelessDisconnected, - SystemControl_WirelessNotAvailable, + SystemControl_NetworkDisconnected, + SystemControl_NetworkNotAvailable, + SystemControl_NetworkWiredConnected, + SystemControl_NetworkWirelessConnected, + SystemControl_NetworkWirelessConnecting, Version } } diff --git a/SafeExamBrowser.I18n/Data/de.xml b/SafeExamBrowser.I18n/Data/de.xml index 8eec4cc5..fb6d4cbc 100644 --- a/SafeExamBrowser.I18n/Data/de.xml +++ b/SafeExamBrowser.I18n/Data/de.xml @@ -597,17 +597,20 @@ Das aktuelle Tastatur-Layout ist "%%LAYOUT%%" - - Verbunden mit "%%NAME%%" - - - Verbinde... - - + Getrennt - - Kein WLAN-Netzwerkadapter verfügbar oder eingestellt + + Kein Netzwerkadapter verfügbar oder eingestellt + + + Verbunden + + + Verbunden mit "%%NAME%%" + + + Verbinde... Version diff --git a/SafeExamBrowser.I18n/Data/en.xml b/SafeExamBrowser.I18n/Data/en.xml index 55bc1311..ab2829f5 100644 --- a/SafeExamBrowser.I18n/Data/en.xml +++ b/SafeExamBrowser.I18n/Data/en.xml @@ -597,18 +597,21 @@ The current keyboard layout is "%%LAYOUT%%" - - Connected to "%%NAME%%" - - - Connecting... - - + Disconnected - + No wireless network adapter available or turned on + + Connected + + + Connected to "%%NAME%%" + + + Connecting... + Version diff --git a/SafeExamBrowser.I18n/Data/fr.xml b/SafeExamBrowser.I18n/Data/fr.xml index 39cfd595..37bbf95b 100644 --- a/SafeExamBrowser.I18n/Data/fr.xml +++ b/SafeExamBrowser.I18n/Data/fr.xml @@ -597,18 +597,21 @@ La disposition actuelle du clavier est "%%LAYOUT%%" - - Connecté à "%%NAME%%" - - - Connection en cours... - - + Déconnecté - + Pas d'adaptateur réseau sans fil disponible ou allumé + + Connecté + + + Connecté à "%%NAME%%" + + + Connection en cours... + Version diff --git a/SafeExamBrowser.I18n/Data/it.xml b/SafeExamBrowser.I18n/Data/it.xml index e095400c..9fb9d6fd 100644 --- a/SafeExamBrowser.I18n/Data/it.xml +++ b/SafeExamBrowser.I18n/Data/it.xml @@ -597,18 +597,21 @@ L'attuale layout della tastiera è "%%LAYOUT%%" - - Collegato a "%%NAME%%" - - - Collegamento... - - + Disconnesso - + Nessun adattatore di rete wireless disponibile o attivato + + Collegato + + + Collegato a "%%NAME%%" + + + Collegamento... + Versione diff --git a/SafeExamBrowser.I18n/Data/zh.xml b/SafeExamBrowser.I18n/Data/zh.xml index 5b3bc2d8..653d2e4c 100644 --- a/SafeExamBrowser.I18n/Data/zh.xml +++ b/SafeExamBrowser.I18n/Data/zh.xml @@ -531,18 +531,21 @@ 当前键盘布局是 "%%LAYOUT%%" - - 已连接到 "%%NAME%%" - - - 正在连接... - - + 连接已断开 - + 没有无线网卡或未启用无线网卡 + + 连接的 + + + 已连接到 "%%NAME%%" + + + 正在连接... + 版本 diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 51aae8ae..c741bf8b 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -149,7 +149,7 @@ namespace SafeExamBrowser.Runtime var xmlParser = new XmlParser(compressor, ModuleLogger(nameof(XmlParser))); var xmlSerializer = new XmlSerializer(ModuleLogger(nameof(XmlSerializer))); - configuration = new ConfigurationRepository(certificateStore, new HashAlgorithm(), repositoryLogger); + configuration = new ConfigurationRepository(certificateStore, repositoryLogger); appConfig = configuration.InitializeAppConfig(); configuration.Register(new BinaryParser( diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs index 5e6dc62d..ff777774 100644 --- a/SafeExamBrowser.Server/ServerProxy.cs +++ b/SafeExamBrowser.Server/ServerProxy.cs @@ -26,8 +26,8 @@ using SafeExamBrowser.Server.Data; using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.Settings.Server; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using Timer = System.Timers.Timer; namespace SafeExamBrowser.Server @@ -45,7 +45,7 @@ namespace SafeExamBrowser.Server private readonly IPowerSupply powerSupply; private readonly ISystemInfo systemInfo; private readonly IUserInfo userInfo; - private readonly IWirelessAdapter wirelessAdapter; + private readonly INetworkAdapter networkAdapter; private ApiVersion1 api; private string connectionToken; @@ -70,7 +70,7 @@ namespace SafeExamBrowser.Server ISystemInfo systemInfo, IUserInfo userInfo, IPowerSupply powerSupply = default, - IWirelessAdapter wirelessAdapter = default) + INetworkAdapter networkAdapter = default) { this.api = new ApiVersion1(); this.appConfig = appConfig; @@ -79,12 +79,12 @@ namespace SafeExamBrowser.Server this.logger = logger; this.logContent = new ConcurrentQueue(); this.logTimer = new Timer(); + this.networkAdapter = networkAdapter; this.parser = new Parser(logger); this.pingTimer = new Timer(); this.powerSupply = powerSupply; this.systemInfo = systemInfo; this.userInfo = userInfo; - this.wirelessAdapter = wirelessAdapter; } public ServerResponse Connect() @@ -226,7 +226,7 @@ namespace SafeExamBrowser.Server public void Initialize(ServerSettings settings) { this.settings = settings; - + httpClient = new HttpClient(); httpClient.BaseAddress = new Uri(settings.ServerUrl); @@ -348,20 +348,20 @@ namespace SafeExamBrowser.Server pingTimer.Start(); logger.Info("Started sending pings."); - if (powerSupply != default(IPowerSupply) && wirelessAdapter != default(IWirelessAdapter)) + if (powerSupply != default && networkAdapter != default) { powerSupply.StatusChanged += PowerSupply_StatusChanged; - wirelessAdapter.NetworksChanged += WirelessAdapter_NetworksChanged; + networkAdapter.Changed += NetworkAdapter_Changed; logger.Info("Started monitoring system components."); } } public void StopConnectivity() { - if (powerSupply != default(IPowerSupply) && wirelessAdapter != default(IWirelessAdapter)) + if (powerSupply != default && networkAdapter != default) { powerSupply.StatusChanged -= PowerSupply_StatusChanged; - wirelessAdapter.NetworksChanged -= WirelessAdapter_NetworksChanged; + networkAdapter.Changed -= NetworkAdapter_Changed; logger.Info("Stopped monitoring system components."); } @@ -477,7 +477,7 @@ namespace SafeExamBrowser.Server SendPowerSupplyStatus(text, value); currentPowerSupplyValue = value; } - else if (connected != connectedToPowergrid) + else if (connected != connectedToPowergrid) { var text = $" Device has been {(connected ? "connected to" : "disconnected from")} power grid"; SendPowerSupplyStatus(text, value); @@ -507,13 +507,13 @@ namespace SafeExamBrowser.Server TryExecute(HttpMethod.Post, api.LogEndpoint, out _, content, contentType, authorization, token); } - private void WirelessAdapter_NetworksChanged() + private void NetworkAdapter_Changed() { const int NOT_CONNECTED = -1; try { - var network = wirelessAdapter.GetNetworks().FirstOrDefault(n => n.Status == WirelessNetworkStatus.Connected); + var network = networkAdapter.GetWirelessNetworks().FirstOrDefault(n => n.Status == ConnectionStatus.Connected); if (network?.SignalStrength != currentWlanValue) { diff --git a/SafeExamBrowser.Settings/UserInterface/ActionCenterSettings.cs b/SafeExamBrowser.Settings/UserInterface/ActionCenterSettings.cs index 3a3f25fb..789b77b7 100644 --- a/SafeExamBrowser.Settings/UserInterface/ActionCenterSettings.cs +++ b/SafeExamBrowser.Settings/UserInterface/ActionCenterSettings.cs @@ -30,7 +30,7 @@ namespace SafeExamBrowser.Settings.UserInterface /// Determines whether the application log is accessible via the action center. /// public bool ShowApplicationLog { get; set; } - + /// /// Determines whether the system control for audio is accessible via the action center. /// @@ -47,8 +47,8 @@ namespace SafeExamBrowser.Settings.UserInterface public bool ShowKeyboardLayout { get; set; } /// - /// Determines whether the system control for the wireless network is accessible via the action center. + /// Determines whether the system control for the network is accessible via the action center. /// - public bool ShowWirelessNetwork { get; set; } + public bool ShowNetwork { get; set; } } } diff --git a/SafeExamBrowser.Settings/UserInterface/TaskbarSettings.cs b/SafeExamBrowser.Settings/UserInterface/TaskbarSettings.cs index da3c35ef..ab6a5c04 100644 --- a/SafeExamBrowser.Settings/UserInterface/TaskbarSettings.cs +++ b/SafeExamBrowser.Settings/UserInterface/TaskbarSettings.cs @@ -47,8 +47,8 @@ namespace SafeExamBrowser.Settings.UserInterface public bool ShowKeyboardLayout { get; set; } /// - /// Determines whether the system control for the wireless network is accessible via the taskbar. + /// Determines whether the system control for the network is accessible via the taskbar. /// - public bool ShowWirelessNetwork { get; set; } + public bool ShowNetwork { get; set; } } } diff --git a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/WirelessNetworkStatus.cs b/SafeExamBrowser.SystemComponents.Contracts/Network/ConnectionStatus.cs similarity index 70% rename from SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/WirelessNetworkStatus.cs rename to SafeExamBrowser.SystemComponents.Contracts/Network/ConnectionStatus.cs index a94f2885..f4975c8e 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/WirelessNetworkStatus.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/Network/ConnectionStatus.cs @@ -6,13 +6,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -namespace SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork +namespace SafeExamBrowser.SystemComponents.Contracts.Network { /// - /// Defines all possible wireless network statuses which can be determined by the application. + /// Defines all possible connection statuses which can be determined by the application. /// - public enum WirelessNetworkStatus + public enum ConnectionStatus { + /// + /// The connection status is not determinable. + /// Undefined = 0, /// diff --git a/SafeExamBrowser.SystemComponents.Contracts/Network/ConnectionType.cs b/SafeExamBrowser.SystemComponents.Contracts/Network/ConnectionType.cs new file mode 100644 index 00000000..ee011dc5 --- /dev/null +++ b/SafeExamBrowser.SystemComponents.Contracts/Network/ConnectionType.cs @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.SystemComponents.Contracts.Network +{ + /// + /// Defines all possible connection types which can be determined by the application. + /// + public enum ConnectionType + { + /// + /// The connection type cannot be determined. + /// + Undefined = 0, + + /// + /// A wired network connection. + /// + Wired, + + /// + /// A wireless network connection. + /// + Wireless + } +} diff --git a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/Events/NetworksChangedEventHandler.cs b/SafeExamBrowser.SystemComponents.Contracts/Network/Events/ChangedEventHandler.cs similarity index 62% rename from SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/Events/NetworksChangedEventHandler.cs rename to SafeExamBrowser.SystemComponents.Contracts/Network/Events/ChangedEventHandler.cs index d2532c83..653174b6 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/Events/NetworksChangedEventHandler.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/Network/Events/ChangedEventHandler.cs @@ -6,10 +6,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -namespace SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork.Events +namespace SafeExamBrowser.SystemComponents.Contracts.Network.Events { /// - /// Indicates that the available wireless networks have changed. + /// Indicates that the network adapter has changed. /// - public delegate void NetworksChangedEventHandler(); + public delegate void ChangedEventHandler(); } diff --git a/SafeExamBrowser.SystemComponents.Contracts/Network/INetworkAdapter.cs b/SafeExamBrowser.SystemComponents.Contracts/Network/INetworkAdapter.cs new file mode 100644 index 00000000..3d469d3d --- /dev/null +++ b/SafeExamBrowser.SystemComponents.Contracts/Network/INetworkAdapter.cs @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Collections.Generic; +using SafeExamBrowser.SystemComponents.Contracts.Network.Events; + +namespace SafeExamBrowser.SystemComponents.Contracts.Network +{ + /// + /// Defines the functionality of the network adapter system component. + /// + public interface INetworkAdapter : ISystemComponent + { + /// + /// The connection status of the network adapter. + /// + ConnectionStatus Status { get; } + + /// + /// The type of the current network connection. + /// + ConnectionType Type { get; } + + /// + /// Fired when the network adapter has changed. + /// + event ChangedEventHandler Changed; + + /// + /// Attempts to connect to the wireless network with the given ID. + /// + void ConnectToWirelessNetwork(Guid id); + + /// + /// Retrieves all currently available wireless networks. + /// + IEnumerable GetWirelessNetworks(); + } +} diff --git a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/IWirelessNetwork.cs b/SafeExamBrowser.SystemComponents.Contracts/Network/IWirelessNetwork.cs similarity index 88% rename from SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/IWirelessNetwork.cs rename to SafeExamBrowser.SystemComponents.Contracts/Network/IWirelessNetwork.cs index 73085ae4..9a1ab290 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/IWirelessNetwork.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/Network/IWirelessNetwork.cs @@ -8,7 +8,7 @@ using System; -namespace SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork +namespace SafeExamBrowser.SystemComponents.Contracts.Network { /// /// Defines a wireless network which can be connected to by the application. @@ -33,6 +33,6 @@ namespace SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork /// /// The connection status of this network. /// - WirelessNetworkStatus Status { get; } + ConnectionStatus Status { get; } } } diff --git a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj index fe9584ab..9087e56b 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj +++ b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj @@ -59,6 +59,7 @@ + @@ -68,14 +69,13 @@ - - - - + + + - + diff --git a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/Events/StatusChangedEventHandler.cs b/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/Events/StatusChangedEventHandler.cs deleted file mode 100644 index 33d76ff3..00000000 --- a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/Events/StatusChangedEventHandler.cs +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -namespace SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork.Events -{ - /// - /// Indicates that the wireless network status has changed. - /// - public delegate void StatusChangedEventHandler(WirelessNetworkStatus status); -} diff --git a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/IWirelessAdapter.cs b/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/IWirelessAdapter.cs deleted file mode 100644 index ecd8e62f..00000000 --- a/SafeExamBrowser.SystemComponents.Contracts/WirelessNetwork/IWirelessAdapter.cs +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -using System; -using System.Collections.Generic; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork.Events; - -namespace SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork -{ - public interface IWirelessAdapter : ISystemComponent - { - /// - /// Fired when the available wireless networks changed. - /// - event NetworksChangedEventHandler NetworksChanged; - - /// - /// Fired when the wireless network status changed. - /// - event StatusChangedEventHandler StatusChanged; - - /// - /// Indicates whether the system has an active wireless network adapter. - /// - bool IsAvailable { get; } - - /// - /// Attempts to connect to the wireless network with the given ID. - /// - void Connect(Guid id); - - /// - /// Retrieves all currently available networks. - /// - IEnumerable GetNetworks(); - } -} diff --git a/SafeExamBrowser.SystemComponents/Network/NetworkAdapter.cs b/SafeExamBrowser.SystemComponents/Network/NetworkAdapter.cs new file mode 100644 index 00000000..766cdf80 --- /dev/null +++ b/SafeExamBrowser.SystemComponents/Network/NetworkAdapter.cs @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Timers; +using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Network; +using SafeExamBrowser.SystemComponents.Contracts.Network.Events; +using SafeExamBrowser.WindowsApi.Contracts; +using SimpleWifi; +using SimpleWifi.Win32; +using SimpleWifi.Win32.Interop; + +namespace SafeExamBrowser.SystemComponents.Network +{ + public class NetworkAdapter : INetworkAdapter + { + private readonly object @lock = new object(); + private readonly ILogger logger; + private readonly INativeMethods nativeMethods; + private readonly List wirelessNetworks; + + private Timer timer; + private Wifi wifi; + + public ConnectionStatus Status { get; private set; } + public ConnectionType Type { get; private set; } + + public event ChangedEventHandler Changed; + + public NetworkAdapter(ILogger logger, INativeMethods nativeMethods) + { + this.logger = logger; + this.nativeMethods = nativeMethods; + this.wirelessNetworks = new List(); + } + + public void ConnectToWirelessNetwork(Guid id) + { + lock (@lock) + { + var network = wirelessNetworks.FirstOrDefault(n => n.Id == id); + + if (network != default) + { + try + { + var request = new AuthRequest(network.AccessPoint); + + logger.Info($"Attempting to connect to '{network.Name}'..."); + + network.AccessPoint.ConnectAsync(request, false, (success) => AccessPoint_OnConnectCompleted(network.Name, success)); + Status = ConnectionStatus.Connecting; + } + catch (Exception e) + { + logger.Error($"Failed to connect to wireless network '{network.Name}!'", e); + } + } + else + { + logger.Warn($"Could not find network with id '{id}'!"); + } + } + + Changed?.Invoke(); + } + + public IEnumerable GetWirelessNetworks() + { + lock (@lock) + { + return new List(wirelessNetworks); + } + } + + public void Initialize() + { + const int FIVE_SECONDS = 5000; + + NetworkChange.NetworkAddressChanged += (o, args) => Update(); + NetworkChange.NetworkAvailabilityChanged += (o, args) => Update(); + + wifi = new Wifi(); + wifi.ConnectionStatusChanged += (o, args) => Update(); + + timer = new Timer(FIVE_SECONDS); + timer.Elapsed += (o, args) => Update(); + timer.AutoReset = true; + timer.Start(); + + Update(); + + logger.Info("Started monitoring the network adapter."); + } + + public void Terminate() + { + if (timer != null) + { + timer.Stop(); + logger.Info("Stopped monitoring the network adapter."); + } + } + + private void AccessPoint_OnConnectCompleted(string name, bool success) + { + lock (@lock) + { + // This handler seems to be called before the connection has been fully established, thus we don't yet set the status to connected... + Status = success ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected; + } + + if (success) + { + logger.Info($"Successfully connected to wireless network '{name}'."); + } + else + { + logger.Error($"Failed to connect to wireless network '{name}!'"); + } + } + + private void Update() + { + try + { + lock (@lock) + { + var hasInternet = nativeMethods.HasInternetConnection(); + var hasWireless = !wifi.NoWifiAvailable && !IsTurnedOff(); + var isConnecting = Status == ConnectionStatus.Connecting; + var previousStatus = Status; + + wirelessNetworks.Clear(); + + if (hasWireless) + { + foreach (var accessPoint in wifi.GetAccessPoints()) + { + // The user may only connect to an already configured or connected wireless network! + if (accessPoint.HasProfile || accessPoint.IsConnected) + { + wirelessNetworks.Add(ToWirelessNetwork(accessPoint)); + } + } + } + + Type = hasWireless ? ConnectionType.Wireless : (hasInternet ? ConnectionType.Wired : ConnectionType.Undefined); + Status = hasInternet ? ConnectionStatus.Connected : (hasWireless && isConnecting ? ConnectionStatus.Connecting : ConnectionStatus.Disconnected); + + if (previousStatus != ConnectionStatus.Connected && Status == ConnectionStatus.Connected) + { + logger.Info("Connection established."); + } + + if (previousStatus != ConnectionStatus.Disconnected && Status == ConnectionStatus.Disconnected) + { + logger.Info("Connection lost."); + } + } + } + catch (Exception e) + { + logger.Error("Failed to update network adapter!", e); + } + + Changed?.Invoke(); + } + + private bool IsTurnedOff() + { + try + { + var client = new WlanClient(); + + foreach (var @interface in client.Interfaces) + { + foreach (var state in @interface.RadioState.PhyRadioState) + { + if (state.dot11SoftwareRadioState == Dot11RadioState.On && state.dot11HardwareRadioState == Dot11RadioState.On) + { + return false; + } + } + } + } + catch (Exception e) + { + logger.Error("Failed to determine the radio state of the wireless adapter(s)! Assuming it is (all are) turned off...", e); + } + + return true; + } + + private WirelessNetwork ToWirelessNetwork(AccessPoint accessPoint) + { + return new WirelessNetwork + { + AccessPoint = accessPoint, + Name = accessPoint.Name, + SignalStrength = Convert.ToInt32(accessPoint.SignalStrength), + Status = accessPoint.IsConnected ? ConnectionStatus.Connected : ConnectionStatus.Disconnected + }; + } + } +} diff --git a/SafeExamBrowser.SystemComponents/WirelessNetwork/WirelessNetwork.cs b/SafeExamBrowser.SystemComponents/Network/WirelessNetwork.cs similarity index 77% rename from SafeExamBrowser.SystemComponents/WirelessNetwork/WirelessNetwork.cs rename to SafeExamBrowser.SystemComponents/Network/WirelessNetwork.cs index ae36d8f3..7cead333 100644 --- a/SafeExamBrowser.SystemComponents/WirelessNetwork/WirelessNetwork.cs +++ b/SafeExamBrowser.SystemComponents/Network/WirelessNetwork.cs @@ -7,10 +7,10 @@ */ using System; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SimpleWifi; -namespace SafeExamBrowser.SystemComponents.WirelessNetwork +namespace SafeExamBrowser.SystemComponents.Network { internal class WirelessNetwork : IWirelessNetwork { @@ -19,7 +19,7 @@ namespace SafeExamBrowser.SystemComponents.WirelessNetwork public Guid Id { get; } public string Name { get; set; } public int SignalStrength { get; set; } - public WirelessNetworkStatus Status { get; set; } + public ConnectionStatus Status { get; set; } public WirelessNetwork() { diff --git a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj index 2247f97a..dbd54cae 100644 --- a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj +++ b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj @@ -101,8 +101,8 @@ - - + + @@ -117,6 +117,10 @@ {903129c6-e236-493b-9ad6-c6a57f647a3a} SafeExamBrowser.SystemComponents.Contracts + + {7016f080-9aa5-41b2-a225-385ad877c171} + SafeExamBrowser.WindowsApi.Contracts + diff --git a/SafeExamBrowser.SystemComponents/WirelessNetwork/WirelessAdapter.cs b/SafeExamBrowser.SystemComponents/WirelessNetwork/WirelessAdapter.cs deleted file mode 100644 index 88f88cf0..00000000 --- a/SafeExamBrowser.SystemComponents/WirelessNetwork/WirelessAdapter.cs +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Timers; -using SafeExamBrowser.Logging.Contracts; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork.Events; -using SimpleWifi; -using SimpleWifi.Win32; -using SimpleWifi.Win32.Interop; - -namespace SafeExamBrowser.SystemComponents.WirelessNetwork -{ - public class WirelessAdapter : IWirelessAdapter - { - private readonly object @lock = new object(); - - private List networks; - private ILogger logger; - private Timer timer; - private Wifi wifi; - - public bool IsAvailable { get; private set; } - - public event NetworksChangedEventHandler NetworksChanged; - public event StatusChangedEventHandler StatusChanged; - - public WirelessAdapter(ILogger logger) - { - this.logger = logger; - this.networks = new List(); - } - - public void Connect(Guid id) - { - lock (@lock) - { - var network = networks.FirstOrDefault(n => n.Id == id); - - if (network != default(WirelessNetwork)) - { - try - { - var request = new AuthRequest(network.AccessPoint); - - logger.Info($"Attempting to connect to '{network.Name}'..."); - network.AccessPoint.ConnectAsync(request, false, (success) => AccessPoint_OnConnectCompleted(network.Name, success)); - StatusChanged?.Invoke(WirelessNetworkStatus.Connecting); - } - catch (Exception e) - { - logger.Error($"Failed to connect to wireless network '{network.Name}!'", e); - } - } - else - { - logger.Warn($"Could not find network with id '{id}'!"); - } - } - } - - public IEnumerable GetNetworks() - { - lock (@lock) - { - return new List(networks); - } - } - - public void Initialize() - { - const int FIVE_SECONDS = 5000; - - wifi = new Wifi(); - wifi.ConnectionStatusChanged += Wifi_ConnectionStatusChanged; - IsAvailable = !wifi.NoWifiAvailable && !IsTurnedOff(); - - if (IsAvailable) - { - UpdateAvailableNetworks(); - - timer = new Timer(FIVE_SECONDS); - timer.Elapsed += Timer_Elapsed; - timer.AutoReset = true; - timer.Start(); - - logger.Info("Started monitoring the wireless network adapter."); - } - else - { - logger.Info("Wireless networks cannot be monitored, as there is no hardware adapter available or it is turned off."); - } - } - - public void Terminate() - { - if (timer != null) - { - timer.Stop(); - logger.Info("Stopped monitoring the wireless network adapter."); - } - } - - private void AccessPoint_OnConnectCompleted(string name, bool success) - { - if (success) - { - logger.Info($"Successfully connected to wireless network '{name}'."); - } - else - { - logger.Error($"Failed to connect to wireless network '{name}!'"); - } - - UpdateAvailableNetworks(); - } - - private void Timer_Elapsed(object sender, ElapsedEventArgs e) - { - UpdateAvailableNetworks(); - } - - private void Wifi_ConnectionStatusChanged(object sender, WifiStatusEventArgs e) - { - UpdateAvailableNetworks(); - } - - private bool IsTurnedOff() - { - try - { - var client = new WlanClient(); - - foreach (var @interface in client.Interfaces) - { - foreach (var state in @interface.RadioState.PhyRadioState) - { - if (state.dot11SoftwareRadioState == Dot11RadioState.On && state.dot11HardwareRadioState == Dot11RadioState.On) - { - return false; - } - } - } - } - catch (Exception e) - { - logger.Error("Failed to determine the radio state of the wireless adapter(s)! Assuming it is (all are) turned off...", e); - } - - return true; - } - - private void UpdateAvailableNetworks() - { - lock (@lock) - { - try - { - networks.Clear(); - - foreach (var accessPoint in wifi.GetAccessPoints()) - { - // The user may only connect to an already configured or connected wireless network! - if (accessPoint.HasProfile || accessPoint.IsConnected) - { - networks.Add(ToNetwork(accessPoint)); - } - } - - NetworksChanged?.Invoke(); - } - catch (Exception e) - { - logger.Error("Failed to update available networks!", e); - } - } - } - - private WirelessNetwork ToNetwork(AccessPoint accessPoint) - { - return new WirelessNetwork - { - AccessPoint = accessPoint, - Name = accessPoint.Name, - SignalStrength = Convert.ToInt32(accessPoint.SignalStrength), - Status = accessPoint.IsConnected ? WirelessNetworkStatus.Connected : WirelessNetworkStatus.Disconnected - }; - } - - private WirelessNetworkStatus ToStatus(WifiStatus status) - { - return status == WifiStatus.Connected ? WirelessNetworkStatus.Connected : WirelessNetworkStatus.Disconnected; - } - } -} diff --git a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs index 4562c727..355c123c 100644 --- a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs @@ -18,8 +18,8 @@ using SafeExamBrowser.Settings.Browser; using SafeExamBrowser.Settings.Proctoring; using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts.Browser; using SafeExamBrowser.UserInterface.Contracts.Proctoring; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -78,6 +78,11 @@ namespace SafeExamBrowser.UserInterface.Contracts /// IWindow CreateLogWindow(ILogger logger); + /// + /// Creates a system control which allows to view and/or change the network connection of the computer. + /// + ISystemControl CreateNetworkControl(INetworkAdapter adapter, Location location); + /// /// Creates a notification control for the given notification, initialized for the specified location. /// @@ -132,10 +137,5 @@ namespace SafeExamBrowser.UserInterface.Contracts /// Creates a new taskview. /// ITaskview CreateTaskview(); - - /// - /// Creates a system control which allows to change the wireless network connection of the computer. - /// - ISystemControl CreateWirelessNetworkControl(IWirelessAdapter wirelessAdapter, Location location); } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkButton.xaml similarity index 96% rename from SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkButton.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkButton.xaml index bb6d5151..a7f53517 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkButton.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkButton.xaml @@ -1,4 +1,4 @@ - NetworkSelected?.Invoke(this, EventArgs.Empty); - IsCurrentTextBlock.Visibility = network.Status == WirelessNetworkStatus.Connected ? Visibility.Visible : Visibility.Hidden; + IsCurrentTextBlock.Visibility = network.Status == ConnectionStatus.Connected ? Visibility.Visible : Visibility.Hidden; NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml similarity index 76% rename from SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkControl.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml index 8e68db1f..87eafde6 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml @@ -1,4 +1,4 @@ - - + @@ -30,10 +30,11 @@ - - - - + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml.cs new file mode 100644 index 00000000..92c3c950 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml.cs @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using FontAwesome.WPF; +using SafeExamBrowser.Core.Contracts.Resources.Icons; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Network; +using SafeExamBrowser.UserInterface.Contracts.Shell; +using SafeExamBrowser.UserInterface.Shared.Utilities; + +namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter +{ + internal partial class NetworkControl : UserControl, ISystemControl + { + private readonly INetworkAdapter adapter; + private readonly IText text; + + internal NetworkControl(INetworkAdapter adapter, IText text) + { + this.adapter = adapter; + this.text = text; + + InitializeComponent(); + InitializeWirelessNetworkControl(); + } + + public void Close() + { + Dispatcher.InvokeAsync(() => Popup.IsOpen = false); + } + + private void InitializeWirelessNetworkControl() + { + var originalBrush = Grid.Background; + + adapter.Changed += () => Dispatcher.InvokeAsync(Update); + Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; + Popup.Closed += (o, args) => Grid.Background = originalBrush; + WirelessIcon.Child = GetWirelessIcon(0); + + Update(); + } + + private void Update() + { + WirelessNetworksStackPanel.Children.Clear(); + + foreach (var network in adapter.GetWirelessNetworks()) + { + var button = new NetworkButton(network); + + button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id); + + if (network.Status == ConnectionStatus.Connected) + { + WirelessIcon.Child = GetWirelessIcon(network.SignalStrength); + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name)); + } + + WirelessNetworksStackPanel.Children.Add(button); + } + + switch (adapter.Type) + { + case ConnectionType.Wired: + Button.IsEnabled = false; + UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected)); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; + break; + case ConnectionType.Wireless: + Button.IsEnabled = true; + WiredIcon.Visibility = Visibility.Collapsed; + WirelessIcon.Visibility = Visibility.Visible; + break; + default: + Button.IsEnabled = false; + UpdateText(text.Get(TextKey.SystemControl_NetworkNotAvailable)); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; + break; + } + + switch (adapter.Status) + { + case ConnectionStatus.Connected: + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green); + NetworkStatusIcon.Spin = false; + break; + case ConnectionStatus.Connecting: + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnecting)); + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray); + NetworkStatusIcon.Spin = true; + NetworkStatusIcon.SpinDuration = 2; + break; + default: + UpdateText(text.Get(TextKey.SystemControl_NetworkDisconnected)); + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange); + NetworkStatusIcon.Spin = false; + WirelessIcon.Child = GetWirelessIcon(0); + break; + } + } + + private void UpdateText(string text) + { + Button.ToolTip = text; + Text.Text = text; + } + + private UIElement GetWirelessIcon(int signalStrength) + { + var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0")); + var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/WiFi_Light_{icon}.xaml"); + var resource = new XamlIconResource { Uri = uri }; + + return IconResourceLoader.Load(resource); + } + } +} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkControl.xaml.cs deleted file mode 100644 index 0f793b65..00000000 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/WirelessNetworkControl.xaml.cs +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -using System; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using FontAwesome.WPF; -using SafeExamBrowser.Core.Contracts.Resources.Icons; -using SafeExamBrowser.I18n.Contracts; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; -using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Shared.Utilities; - -namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter -{ - internal partial class WirelessNetworkControl : UserControl, ISystemControl - { - private IWirelessAdapter wirelessAdapter; - private IText text; - - internal WirelessNetworkControl(IWirelessAdapter wirelessAdapter, IText text) - { - this.wirelessAdapter = wirelessAdapter; - this.text = text; - - InitializeComponent(); - InitializeWirelessNetworkControl(); - } - - public void Close() - { - Dispatcher.InvokeAsync(() => Popup.IsOpen = false); - } - - private void InitializeWirelessNetworkControl() - { - var originalBrush = Grid.Background; - - SignalStrengthIcon.Child = GetIcon(0); - Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); - Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; - - if (wirelessAdapter.IsAvailable) - { - wirelessAdapter.NetworksChanged += WirelessAdapter_NetworksChanged; - wirelessAdapter.StatusChanged += WirelessAdapter_StatusChanged; - UpdateNetworks(); - } - else - { - Button.IsEnabled = false; - NoAdapterIcon.Visibility = Visibility.Visible; - UpdateText(text.Get(TextKey.SystemControl_WirelessNotAvailable)); - } - } - - private void WirelessAdapter_NetworksChanged() - { - Dispatcher.InvokeAsync(UpdateNetworks); - } - - private void WirelessAdapter_StatusChanged(WirelessNetworkStatus status) - { - Dispatcher.InvokeAsync(() => UpdateStatus(status)); - } - - private void UpdateNetworks() - { - var status = WirelessNetworkStatus.Disconnected; - - NetworksStackPanel.Children.Clear(); - - foreach (var network in wirelessAdapter.GetNetworks()) - { - var button = new WirelessNetworkButton(network); - - button.NetworkSelected += (o, args) => wirelessAdapter.Connect(network.Id); - - if (network.Status == WirelessNetworkStatus.Connected) - { - status = WirelessNetworkStatus.Connected; - SignalStrengthIcon.Child = GetIcon(network.SignalStrength); - UpdateText(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", network.Name)); - } - - NetworksStackPanel.Children.Add(button); - } - - UpdateStatus(status); - } - - private void UpdateStatus(WirelessNetworkStatus status) - { - LoadingIcon.Visibility = Visibility.Collapsed; - SignalStrengthIcon.Visibility = Visibility.Visible; - NetworkStatusIcon.Visibility = Visibility.Visible; - - switch (status) - { - case WirelessNetworkStatus.Connected: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Check, Brushes.Green); - break; - case WirelessNetworkStatus.Connecting: - LoadingIcon.Visibility = Visibility.Visible; - SignalStrengthIcon.Visibility = Visibility.Collapsed; - NetworkStatusIcon.Visibility = Visibility.Collapsed; - UpdateText(text.Get(TextKey.SystemControl_WirelessConnecting)); - break; - default: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Close, Brushes.Orange); - SignalStrengthIcon.Child = GetIcon(0); - UpdateText(text.Get(TextKey.SystemControl_WirelessDisconnected)); - break; - } - } - - private void UpdateText(string text) - { - Button.ToolTip = text; - Text.Text = text; - } - - 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.Desktop;component/Images/WiFi_Light_{icon}.xaml"); - var resource = new XamlIconResource { Uri = uri }; - - return IconResourceLoader.Load(resource); - } - } -} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkButton.xaml similarity index 96% rename from SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkButton.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkButton.xaml index ede4473f..b72e3c47 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkButton.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkButton.xaml @@ -1,4 +1,4 @@ - NetworkSelected?.Invoke(this, EventArgs.Empty); - IsCurrentTextBlock.Visibility = network.Status == WirelessNetworkStatus.Connected ? Visibility.Visible : Visibility.Hidden; + IsCurrentTextBlock.Visibility = network.Status == ConnectionStatus.Connected ? Visibility.Visible : Visibility.Hidden; NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml similarity index 73% rename from SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkControl.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml index a9b0a640..cd106290 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml @@ -1,4 +1,4 @@ - - + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml.cs similarity index 50% rename from SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkControl.xaml.cs rename to SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml.cs index ec5ca2b3..aede61e4 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/WirelessNetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml.cs @@ -15,20 +15,20 @@ using System.Windows.Media; using FontAwesome.WPF; using SafeExamBrowser.Core.Contracts.Resources.Icons; using SafeExamBrowser.I18n.Contracts; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.UserInterface.Shared.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar { - internal partial class WirelessNetworkControl : UserControl, ISystemControl + internal partial class NetworkControl : UserControl, ISystemControl { - private IWirelessAdapter wirelessAdapter; - private IText text; + private readonly INetworkAdapter adapter; + private readonly IText text; - internal WirelessNetworkControl(IWirelessAdapter wirelessAdapter, IText text) + internal NetworkControl(INetworkAdapter adapter, IText text) { - this.wirelessAdapter = wirelessAdapter; + this.adapter = adapter; this.text = text; InitializeComponent(); @@ -44,11 +44,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar { var originalBrush = Button.Background; - SignalStrengthIcon.Child = GetIcon(0); + adapter.Changed += () => Dispatcher.InvokeAsync(Update); Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + WirelessIcon.Child = GetWirelessIcon(0); Popup.Opened += (o, args) => { @@ -62,18 +63,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar Button.Background = originalBrush; }; - if (wirelessAdapter.IsAvailable) - { - wirelessAdapter.NetworksChanged += WirelessAdapter_NetworksChanged; - wirelessAdapter.StatusChanged += WirelessAdapter_StatusChanged; - UpdateNetworks(); - } - else - { - Button.IsEnabled = false; - NoAdapterIcon.Visibility = Visibility.Visible; - UpdateText(text.Get(TextKey.SystemControl_WirelessNotAvailable)); - } + Update(); } private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset) @@ -84,72 +74,70 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar }; } - private void WirelessAdapter_NetworksChanged() + private void Update() { - Dispatcher.InvokeAsync(UpdateNetworks); - } + WirelessNetworksStackPanel.Children.Clear(); - private void WirelessAdapter_StatusChanged(WirelessNetworkStatus status) - { - Dispatcher.InvokeAsync(() => UpdateStatus(status)); - } - - private void UpdateNetworks() - { - var status = WirelessNetworkStatus.Disconnected; - - NetworksStackPanel.Children.Clear(); - - foreach (var network in wirelessAdapter.GetNetworks()) + foreach (var network in adapter.GetWirelessNetworks()) { - var button = new WirelessNetworkButton(network); + var button = new NetworkButton(network); - button.NetworkSelected += (o, args) => wirelessAdapter.Connect(network.Id); + button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id); - if (network.Status == WirelessNetworkStatus.Connected) + if (network.Status == ConnectionStatus.Connected) { - status = WirelessNetworkStatus.Connected; - SignalStrengthIcon.Child = GetIcon(network.SignalStrength); - UpdateText(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", network.Name)); + WirelessIcon.Child = GetWirelessIcon(network.SignalStrength); + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name); } - NetworksStackPanel.Children.Add(button); + WirelessNetworksStackPanel.Children.Add(button); } - UpdateStatus(status); - } - - private void UpdateStatus(WirelessNetworkStatus status) - { - LoadingIcon.Visibility = Visibility.Collapsed; - SignalStrengthIcon.Visibility = Visibility.Visible; - NetworkStatusIcon.Visibility = Visibility.Visible; - - switch (status) + switch (adapter.Type) { - case WirelessNetworkStatus.Connected: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Check, Brushes.Green); + case ConnectionType.Wired: + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWiredConnected); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; break; - case WirelessNetworkStatus.Connecting: - LoadingIcon.Visibility = Visibility.Visible; - SignalStrengthIcon.Visibility = Visibility.Collapsed; - NetworkStatusIcon.Visibility = Visibility.Collapsed; - UpdateText(text.Get(TextKey.SystemControl_WirelessConnecting)); + case ConnectionType.Wireless: + Button.IsEnabled = true; + WiredIcon.Visibility = Visibility.Collapsed; + WirelessIcon.Visibility = Visibility.Visible; break; default: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Close, Brushes.Orange); - SignalStrengthIcon.Child = GetIcon(0); - UpdateText(text.Get(TextKey.SystemControl_WirelessDisconnected)); + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkNotAvailable); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; + break; + } + + switch (adapter.Status) + { + case ConnectionStatus.Connected: + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green); + NetworkStatusIcon.Spin = false; + break; + case ConnectionStatus.Connecting: + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnecting); + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray); + NetworkStatusIcon.Spin = true; + NetworkStatusIcon.SpinDuration = 2; + break; + default: + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkDisconnected); + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange); + NetworkStatusIcon.Spin = false; + WirelessIcon.Child = GetWirelessIcon(0); break; } } - private void UpdateText(string text) - { - Button.ToolTip = text; - } - - private UIElement GetIcon(int signalStrength) + private UIElement GetWirelessIcon(int signalStrength) { var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0")); var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/WiFi_{icon}.xaml"); diff --git a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj index 9353cbc8..47aa672f 100644 --- a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj +++ b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj @@ -109,11 +109,11 @@ QuitButton.xaml - - WirelessNetworkButton.xaml + + NetworkButton.xaml - - WirelessNetworkControl.xaml + + NetworkControl.xaml DownloadItemControl.xaml @@ -145,11 +145,11 @@ QuitButton.xaml - - WirelessNetworkButton.xaml + + NetworkButton.xaml - - WirelessNetworkControl.xaml + + NetworkControl.xaml WindowControl.xaml @@ -263,11 +263,11 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile - + Designer MSBuild:Compile @@ -451,11 +451,11 @@ MSBuild:Compile Designer - + Designer MSBuild:Compile - + Designer MSBuild:Compile diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs index 0d6e8c75..f84c0a5e 100644 --- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs @@ -22,8 +22,8 @@ using SafeExamBrowser.Settings.Browser; using SafeExamBrowser.Settings.Proctoring; using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser; using SafeExamBrowser.UserInterface.Contracts.Proctoring; @@ -37,7 +37,7 @@ namespace SafeExamBrowser.UserInterface.Desktop { public class UserInterfaceFactory : IUserInterfaceFactory { - private IText text; + private readonly IText text; public UserInterfaceFactory(IText text) { @@ -131,6 +131,18 @@ namespace SafeExamBrowser.UserInterface.Desktop return window; } + public ISystemControl CreateNetworkControl(INetworkAdapter adapter, Location location) + { + if (location == Location.ActionCenter) + { + return new Controls.ActionCenter.NetworkControl(adapter, text); + } + else + { + return new Controls.Taskbar.NetworkControl(adapter, text); + } + } + public INotificationControl CreateNotificationControl(INotification notification, Location location) { if (location == Location.ActionCenter) @@ -226,18 +238,6 @@ namespace SafeExamBrowser.UserInterface.Desktop return new Taskview(); } - public ISystemControl CreateWirelessNetworkControl(IWirelessAdapter wirelessAdapter, Location location) - { - if (location == Location.ActionCenter) - { - return new Controls.ActionCenter.WirelessNetworkControl(wirelessAdapter, text); - } - else - { - return new Controls.Taskbar.WirelessNetworkControl(wirelessAdapter, text); - } - } - private void InitializeFontAwesome() { // To be able to use FontAwesome in XAML icon resources, we need to make sure that the FontAwesome.WPF assembly is loaded into diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkButton.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkButton.xaml similarity index 96% rename from SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkButton.xaml rename to SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkButton.xaml index b85b316f..32adafd7 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkButton.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkButton.xaml @@ -1,4 +1,4 @@ - NetworkSelected?.Invoke(this, EventArgs.Empty); - IsCurrentTextBlock.Visibility = network.Status == WirelessNetworkStatus.Connected ? Visibility.Visible : Visibility.Hidden; + IsCurrentTextBlock.Visibility = network.Status == ConnectionStatus.Connected ? Visibility.Visible : Visibility.Hidden; NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml similarity index 76% rename from SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkControl.xaml rename to SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml index b69ad39d..7f391664 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml @@ -1,4 +1,4 @@ - - + @@ -30,10 +30,11 @@ - - - - + + + + + diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml.cs new file mode 100644 index 00000000..f1b1352f --- /dev/null +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml.cs @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using FontAwesome.WPF; +using SafeExamBrowser.Core.Contracts.Resources.Icons; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Network; +using SafeExamBrowser.UserInterface.Contracts.Shell; +using SafeExamBrowser.UserInterface.Shared.Utilities; + +namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter +{ + internal partial class NetworkControl : UserControl, ISystemControl + { + private readonly INetworkAdapter adapter; + private readonly IText text; + + internal NetworkControl(INetworkAdapter adapter, IText text) + { + this.adapter = adapter; + this.text = text; + + InitializeComponent(); + InitializeWirelessNetworkControl(); + } + + public void Close() + { + Dispatcher.InvokeAsync(() => Popup.IsOpen = false); + } + + private void InitializeWirelessNetworkControl() + { + var originalBrush = Grid.Background; + + adapter.Changed += () => Dispatcher.InvokeAsync(Update); + Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; + Popup.Closed += (o, args) => Grid.Background = originalBrush; + WirelessIcon.Child = GetWirelessIcon(0); + + Update(); + } + + private void Update() + { + WirelessNetworksStackPanel.Children.Clear(); + + foreach (var network in adapter.GetWirelessNetworks()) + { + var button = new NetworkButton(network); + + button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id); + + if (network.Status == ConnectionStatus.Connected) + { + WirelessIcon.Child = GetWirelessIcon(network.SignalStrength); + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name)); + } + + WirelessNetworksStackPanel.Children.Add(button); + } + + switch (adapter.Type) + { + case ConnectionType.Wired: + Button.IsEnabled = false; + UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected)); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; + break; + case ConnectionType.Wireless: + Button.IsEnabled = true; + WiredIcon.Visibility = Visibility.Collapsed; + WirelessIcon.Visibility = Visibility.Visible; + break; + default: + Button.IsEnabled = false; + UpdateText(text.Get(TextKey.SystemControl_NetworkNotAvailable)); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; + break; + } + + switch (adapter.Status) + { + case ConnectionStatus.Connected: + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green); + NetworkStatusIcon.Spin = false; + break; + case ConnectionStatus.Connecting: + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnecting)); + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray); + NetworkStatusIcon.Spin = true; + NetworkStatusIcon.SpinDuration = 2; + break; + default: + UpdateText(text.Get(TextKey.SystemControl_NetworkDisconnected)); + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange); + NetworkStatusIcon.Spin = false; + WirelessIcon.Child = GetWirelessIcon(0); + break; + } + } + + private void UpdateText(string text) + { + Button.ToolTip = text; + Text.Text = text; + } + + private UIElement GetWirelessIcon(int signalStrength) + { + var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0")); + var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/WiFi_Light_{icon}.xaml"); + var resource = new XamlIconResource { Uri = uri }; + + return IconResourceLoader.Load(resource); + } + } +} diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkControl.xaml.cs deleted file mode 100644 index 67faaf58..00000000 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/WirelessNetworkControl.xaml.cs +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -using System; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using FontAwesome.WPF; -using SafeExamBrowser.Core.Contracts.Resources.Icons; -using SafeExamBrowser.I18n.Contracts; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; -using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Shared.Utilities; - -namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter -{ - internal partial class WirelessNetworkControl : UserControl, ISystemControl - { - private IWirelessAdapter wirelessAdapter; - private IText text; - - internal WirelessNetworkControl(IWirelessAdapter wirelessAdapter, IText text) - { - this.wirelessAdapter = wirelessAdapter; - this.text = text; - - InitializeComponent(); - InitializeWirelessNetworkControl(); - } - - public void Close() - { - Dispatcher.InvokeAsync(() => Popup.IsOpen = false); - } - - private void InitializeWirelessNetworkControl() - { - var originalBrush = Grid.Background; - - SignalStrengthIcon.Child = GetIcon(0); - Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); - Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; - - if (wirelessAdapter.IsAvailable) - { - wirelessAdapter.NetworksChanged += WirelessAdapter_NetworksChanged; - wirelessAdapter.StatusChanged += WirelessAdapter_StatusChanged; - UpdateNetworks(); - } - else - { - Button.IsEnabled = false; - NoAdapterIcon.Visibility = Visibility.Visible; - UpdateText(text.Get(TextKey.SystemControl_WirelessNotAvailable)); - } - } - - private void WirelessAdapter_NetworksChanged() - { - Dispatcher.InvokeAsync(UpdateNetworks); - } - - private void WirelessAdapter_StatusChanged(WirelessNetworkStatus status) - { - Dispatcher.InvokeAsync(() => UpdateStatus(status)); - } - - private void UpdateNetworks() - { - var status = WirelessNetworkStatus.Disconnected; - - NetworksStackPanel.Children.Clear(); - - foreach (var network in wirelessAdapter.GetNetworks()) - { - var button = new WirelessNetworkButton(network); - - button.NetworkSelected += (o, args) => wirelessAdapter.Connect(network.Id); - - if (network.Status == WirelessNetworkStatus.Connected) - { - status = WirelessNetworkStatus.Connected; - SignalStrengthIcon.Child = GetIcon(network.SignalStrength); - UpdateText(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", network.Name)); - } - - NetworksStackPanel.Children.Add(button); - } - - UpdateStatus(status); - } - - private void UpdateStatus(WirelessNetworkStatus status) - { - LoadingIcon.Visibility = Visibility.Collapsed; - SignalStrengthIcon.Visibility = Visibility.Visible; - NetworkStatusIcon.Visibility = Visibility.Visible; - - switch (status) - { - case WirelessNetworkStatus.Connected: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Check, Brushes.Green); - break; - case WirelessNetworkStatus.Connecting: - LoadingIcon.Visibility = Visibility.Visible; - SignalStrengthIcon.Visibility = Visibility.Collapsed; - NetworkStatusIcon.Visibility = Visibility.Collapsed; - UpdateText(text.Get(TextKey.SystemControl_WirelessConnecting)); - break; - default: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Close, Brushes.Orange); - SignalStrengthIcon.Child = GetIcon(0); - UpdateText(text.Get(TextKey.SystemControl_WirelessDisconnected)); - break; - } - } - - private void UpdateText(string text) - { - Button.ToolTip = text; - Text.Text = text; - } - - 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.Mobile;component/Images/WiFi_Light_{icon}.xaml"); - var resource = new XamlIconResource { Uri = uri }; - - return IconResourceLoader.Load(resource); - } - } -} diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkButton.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkButton.xaml similarity index 96% rename from SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkButton.xaml rename to SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkButton.xaml index e0377dd1..e04e651a 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkButton.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkButton.xaml @@ -1,4 +1,4 @@ - NetworkSelected?.Invoke(this, EventArgs.Empty); - IsCurrentTextBlock.Visibility = network.Status == WirelessNetworkStatus.Connected ? Visibility.Visible : Visibility.Hidden; + IsCurrentTextBlock.Visibility = network.Status == ConnectionStatus.Connected ? Visibility.Visible : Visibility.Hidden; NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml similarity index 73% rename from SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkControl.xaml rename to SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml index 7ab16afd..97fbf580 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml @@ -1,4 +1,4 @@ - - + diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml.cs similarity index 50% rename from SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkControl.xaml.cs rename to SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml.cs index d3e77e67..04c04b7e 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/WirelessNetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml.cs @@ -15,20 +15,20 @@ using System.Windows.Media; using FontAwesome.WPF; using SafeExamBrowser.Core.Contracts.Resources.Icons; using SafeExamBrowser.I18n.Contracts; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.UserInterface.Shared.Utilities; namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar { - internal partial class WirelessNetworkControl : UserControl, ISystemControl + internal partial class NetworkControl : UserControl, ISystemControl { - private IWirelessAdapter wirelessAdapter; - private IText text; + private readonly INetworkAdapter adapter; + private readonly IText text; - internal WirelessNetworkControl(IWirelessAdapter wirelessAdapter, IText text) + internal NetworkControl(INetworkAdapter adapter, IText text) { - this.wirelessAdapter = wirelessAdapter; + this.adapter = adapter; this.text = text; InitializeComponent(); @@ -44,11 +44,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar { var originalBrush = Button.Background; - SignalStrengthIcon.Child = GetIcon(0); + adapter.Changed += () => Dispatcher.InvokeAsync(Update); Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + WirelessIcon.Child = GetWirelessIcon(0); Popup.Opened += (o, args) => { @@ -62,18 +63,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar Button.Background = originalBrush; }; - if (wirelessAdapter.IsAvailable) - { - wirelessAdapter.NetworksChanged += WirelessAdapter_NetworksChanged; - wirelessAdapter.StatusChanged += WirelessAdapter_StatusChanged; - UpdateNetworks(); - } - else - { - Button.IsEnabled = false; - NoAdapterIcon.Visibility = Visibility.Visible; - UpdateText(text.Get(TextKey.SystemControl_WirelessNotAvailable)); - } + Update(); } private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset) @@ -84,72 +74,70 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar }; } - private void WirelessAdapter_NetworksChanged() + private void Update() { - Dispatcher.InvokeAsync(UpdateNetworks); - } + WirelessNetworksStackPanel.Children.Clear(); - private void WirelessAdapter_StatusChanged(WirelessNetworkStatus status) - { - Dispatcher.InvokeAsync(() => UpdateStatus(status)); - } - - private void UpdateNetworks() - { - var status = WirelessNetworkStatus.Disconnected; - - NetworksStackPanel.Children.Clear(); - - foreach (var network in wirelessAdapter.GetNetworks()) + foreach (var network in adapter.GetWirelessNetworks()) { - var button = new WirelessNetworkButton(network); + var button = new NetworkButton(network); - button.NetworkSelected += (o, args) => wirelessAdapter.Connect(network.Id); + button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Id); - if (network.Status == WirelessNetworkStatus.Connected) + if (network.Status == ConnectionStatus.Connected) { - status = WirelessNetworkStatus.Connected; - SignalStrengthIcon.Child = GetIcon(network.SignalStrength); - UpdateText(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", network.Name)); + WirelessIcon.Child = GetWirelessIcon(network.SignalStrength); + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name); } - NetworksStackPanel.Children.Add(button); + WirelessNetworksStackPanel.Children.Add(button); } - UpdateStatus(status); - } - - private void UpdateStatus(WirelessNetworkStatus status) - { - LoadingIcon.Visibility = Visibility.Collapsed; - SignalStrengthIcon.Visibility = Visibility.Visible; - NetworkStatusIcon.Visibility = Visibility.Visible; - - switch (status) + switch (adapter.Type) { - case WirelessNetworkStatus.Connected: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Check, Brushes.Green); + case ConnectionType.Wired: + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWiredConnected); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; break; - case WirelessNetworkStatus.Connecting: - LoadingIcon.Visibility = Visibility.Visible; - SignalStrengthIcon.Visibility = Visibility.Collapsed; - NetworkStatusIcon.Visibility = Visibility.Collapsed; - UpdateText(text.Get(TextKey.SystemControl_WirelessConnecting)); + case ConnectionType.Wireless: + Button.IsEnabled = true; + WiredIcon.Visibility = Visibility.Collapsed; + WirelessIcon.Visibility = Visibility.Visible; break; default: - NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Close, Brushes.Orange); - SignalStrengthIcon.Child = GetIcon(0); - UpdateText(text.Get(TextKey.SystemControl_WirelessDisconnected)); + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkNotAvailable); + WiredIcon.Visibility = Visibility.Visible; + WirelessIcon.Visibility = Visibility.Collapsed; + break; + } + + switch (adapter.Status) + { + case ConnectionStatus.Connected: + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green); + NetworkStatusIcon.Spin = false; + break; + case ConnectionStatus.Connecting: + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnecting); + NetworkStatusIcon.Rotation = 0; + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray); + NetworkStatusIcon.Spin = true; + NetworkStatusIcon.SpinDuration = 2; + break; + default: + Button.ToolTip = text.Get(TextKey.SystemControl_NetworkDisconnected); + NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange); + NetworkStatusIcon.Spin = false; + WirelessIcon.Child = GetWirelessIcon(0); break; } } - private void UpdateText(string text) - { - Button.ToolTip = text; - } - - private UIElement GetIcon(int signalStrength) + private UIElement GetWirelessIcon(int signalStrength) { var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0")); var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/WiFi_{icon}.xaml"); diff --git a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj index 3c9e55f5..2a43e1aa 100644 --- a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj +++ b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj @@ -110,11 +110,11 @@ QuitButton.xaml - - WirelessNetworkButton.xaml + + NetworkButton.xaml - - WirelessNetworkControl.xaml + + NetworkControl.xaml DownloadItemControl.xaml @@ -146,11 +146,11 @@ QuitButton.xaml - - WirelessNetworkButton.xaml + + NetworkButton.xaml - - WirelessNetworkControl.xaml + + NetworkControl.xaml WindowControl.xaml @@ -321,11 +321,11 @@ MSBuild:Compile Designer - + MSBuild:Compile Designer - + MSBuild:Compile Designer @@ -369,11 +369,11 @@ MSBuild:Compile Designer - + MSBuild:Compile Designer - + MSBuild:Compile Designer diff --git a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs index 42425f62..3625a500 100644 --- a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs @@ -22,8 +22,8 @@ using SafeExamBrowser.Settings.Browser; using SafeExamBrowser.Settings.Proctoring; using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; +using SafeExamBrowser.SystemComponents.Contracts.Network; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; -using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser; using SafeExamBrowser.UserInterface.Contracts.Proctoring; @@ -37,7 +37,7 @@ namespace SafeExamBrowser.UserInterface.Mobile { public class UserInterfaceFactory : IUserInterfaceFactory { - private IText text; + private readonly IText text; public UserInterfaceFactory(IText text) { @@ -131,6 +131,18 @@ namespace SafeExamBrowser.UserInterface.Mobile return window; } + public ISystemControl CreateNetworkControl(INetworkAdapter adapter, Location location) + { + if (location == Location.ActionCenter) + { + return new Controls.ActionCenter.NetworkControl(adapter, text); + } + else + { + return new Controls.Taskbar.NetworkControl(adapter, text); + } + } + public INotificationControl CreateNotificationControl(INotification notification, Location location) { if (location == Location.ActionCenter) @@ -226,18 +238,6 @@ namespace SafeExamBrowser.UserInterface.Mobile return new Taskview(); } - public ISystemControl CreateWirelessNetworkControl(IWirelessAdapter wirelessAdapter, Location location) - { - if (location == Location.ActionCenter) - { - return new Controls.ActionCenter.WirelessNetworkControl(wirelessAdapter, text); - } - else - { - return new Controls.Taskbar.WirelessNetworkControl(wirelessAdapter, text); - } - } - private void InitializeFontAwesome() { // To be able to use FontAwesome in XAML icon resources, we need to make sure that the FontAwesome.WPF assembly is loaded into diff --git a/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs b/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs index 1ffdb900..22431af6 100644 --- a/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs +++ b/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs @@ -108,6 +108,11 @@ namespace SafeExamBrowser.WindowsApi.Contracts /// IBounds GetWorkingArea(); + /// + /// Determines whether this computer is connected to the internet. Returns true if successful, otherwise false. + /// + bool HasInternetConnection(); + /// /// Hides the given window. Returns true if successful, otherwise false. /// diff --git a/SafeExamBrowser.WindowsApi/NativeMethods.cs b/SafeExamBrowser.WindowsApi/NativeMethods.cs index 7b99c2c1..ce0e2baa 100644 --- a/SafeExamBrowser.WindowsApi/NativeMethods.cs +++ b/SafeExamBrowser.WindowsApi/NativeMethods.cs @@ -24,9 +24,9 @@ namespace SafeExamBrowser.WindowsApi { public class NativeMethods : INativeMethods { - private ConcurrentDictionary KeyboardHooks = new ConcurrentDictionary(); - private ConcurrentDictionary MouseHooks = new ConcurrentDictionary(); - private ConcurrentDictionary SystemHooks = new ConcurrentDictionary(); + private readonly ConcurrentDictionary KeyboardHooks = new ConcurrentDictionary(); + private readonly ConcurrentDictionary MouseHooks = new ConcurrentDictionary(); + private readonly ConcurrentDictionary SystemHooks = new ConcurrentDictionary(); /// /// Upon finalization, unregister all active system events and hooks... @@ -245,6 +245,11 @@ namespace SafeExamBrowser.WindowsApi return workingArea.ToBounds(); } + public bool HasInternetConnection() + { + return WinInet.InternetGetConnectedState(out _, 0); + } + public bool HideWindow(IntPtr window) { return User32.ShowWindow(window, (int) ShowWindowCommand.Hide); diff --git a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj index 63861e8d..bf46e48a 100644 --- a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj +++ b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj @@ -92,6 +92,7 @@ + diff --git a/SafeExamBrowser.WindowsApi/WinInet.cs b/SafeExamBrowser.WindowsApi/WinInet.cs new file mode 100644 index 00000000..f81a5242 --- /dev/null +++ b/SafeExamBrowser.WindowsApi/WinInet.cs @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System.Runtime.InteropServices; + +namespace SafeExamBrowser.WindowsApi +{ + /// + /// Provides access to the native Windows API exposed by wininet.dll. + /// + internal static class WinInet + { + [DllImport("wininet.dll", SetLastError = true)] + internal static extern bool InternetGetConnectedState(out int description, int reservedValue); + } +}