diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 23636d42..bc497bd9 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -103,7 +103,6 @@ namespace SafeExamBrowser.Client 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(registry); taskbar = uiFactory.CreateTaskbar(ModuleLogger("Taskbar")); @@ -128,6 +127,7 @@ namespace SafeExamBrowser.Client operations.Enqueue(new ConfigurationOperation(context, logger, runtimeProxy)); operations.Enqueue(new DelegateOperation(UpdateAppConfig)); operations.Enqueue(new DelegateOperation(BuildIntegrityModule)); + operations.Enqueue(new DelegateOperation(BuildPowerSupply)); operations.Enqueue(new LazyInitializationOperation(BuildClientHostOperation)); operations.Enqueue(new ClientHostDisconnectionOperation(context, logger, FIVE_SECONDS)); operations.Enqueue(new LazyInitializationOperation(BuildKeyboardInterceptorOperation)); @@ -265,6 +265,11 @@ namespace SafeExamBrowser.Client context.IntegrityModule = new IntegrityModule(context.AppConfig, ModuleLogger(nameof(IntegrityModule))); } + private void BuildPowerSupply() + { + powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)), context.Settings.PowerSupply); + } + private IOperation BuildKeyboardInterceptorOperation() { var keyboardInterceptor = new KeyboardInterceptor(ModuleLogger(nameof(KeyboardInterceptor)), nativeMethods, context.Settings.Keyboard); diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs index ae25b419..cff9346b 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapping/UserInterfaceDataMapper.cs @@ -20,18 +20,24 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping case Keys.UserInterface.ActionCenter.EnableActionCenter: MapEnableActionCenter(settings, value); break; - case Keys.UserInterface.ShowAudio: + case Keys.UserInterface.SystemControls.Audio.Show: MapShowAudio(settings, value); break; - case Keys.UserInterface.ShowClock: + case Keys.UserInterface.SystemControls.Clock.Show: MapShowClock(settings, value); break; - case Keys.UserInterface.ShowKeyboardLayout: + case Keys.UserInterface.SystemControls.KeyboardLayout.Show: MapShowKeyboardLayout(settings, value); break; - case Keys.UserInterface.ShowNetwork: + case Keys.UserInterface.SystemControls.Network.Show: MapShowNetwork(settings, value); break; + case Keys.UserInterface.SystemControls.PowerSupply.ChargeThresholdCritical: + MapChargeThresholdCritical(settings, value); + break; + case Keys.UserInterface.SystemControls.PowerSupply.ChargeThresholdLow: + MapChargeThresholdLow(settings, value); + break; case Keys.UserInterface.Taskbar.EnableTaskbar: MapEnableTaskbar(settings, value); break; @@ -88,6 +94,22 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping } } + private void MapChargeThresholdCritical(AppSettings settings, object value) + { + if (value is double threshold) + { + settings.PowerSupply.ChargeThresholdCritical = threshold; + } + } + + private void MapChargeThresholdLow(AppSettings settings, object value) + { + if (value is double threshold) + { + settings.PowerSupply.ChargeThresholdLow = threshold; + } + } + private void MapEnableTaskbar(AppSettings settings, object value) { if (value is bool enable) diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs index 67d0df2b..db003f02 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs @@ -235,6 +235,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData settings.Mouse.AllowMiddleButton = false; settings.Mouse.AllowRightButton = true; + settings.PowerSupply.ChargeThresholdCritical = 0.1; + settings.PowerSupply.ChargeThresholdLow = 0.2; + settings.Proctoring.Enabled = false; settings.Proctoring.ForceRaiseHandMessage = false; settings.Proctoring.JitsiMeet.AllowChat = false; diff --git a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs index 6625ced2..81e965f3 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs @@ -334,10 +334,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData internal static class UserInterface { - internal const string ShowAudio = "audioControlEnabled"; - internal const string ShowClock = "showTime"; - internal const string ShowKeyboardLayout = "showInputLanguage"; - internal const string ShowNetwork = "allowWlan"; internal const string UserInterfaceMode = "touchOptimized"; internal static class ActionCenter @@ -345,6 +341,35 @@ namespace SafeExamBrowser.Configuration.ConfigurationData internal const string EnableActionCenter = "showSideMenu"; } + internal static class SystemControls + { + internal static class Audio + { + internal const string Show = "audioControlEnabled"; + } + + internal static class Clock + { + internal const string Show = "showTime"; + } + + internal static class KeyboardLayout + { + internal const string Show = "showInputLanguage"; + } + + internal static class Network + { + internal const string Show = "allowWlan"; + } + + internal static class PowerSupply + { + internal const string ChargeThresholdCritical = "batteryChargeThresholdCritical"; + internal const string ChargeThresholdLow = "batteryChargeThresholdLow"; + } + } + internal static class Taskbar { internal const string EnableTaskbar = "showTaskBar"; diff --git a/SafeExamBrowser.Settings/AppSettings.cs b/SafeExamBrowser.Settings/AppSettings.cs index 5a4a2632..6ee8d039 100644 --- a/SafeExamBrowser.Settings/AppSettings.cs +++ b/SafeExamBrowser.Settings/AppSettings.cs @@ -72,6 +72,11 @@ namespace SafeExamBrowser.Settings /// public MouseSettings Mouse { get; set; } + /// + /// All settings related to the power supply. + /// + public PowerSupplySettings PowerSupply { get; set; } + /// /// All proctoring-related settings. /// @@ -121,6 +126,7 @@ namespace SafeExamBrowser.Settings Display = new DisplaySettings(); Keyboard = new KeyboardSettings(); Mouse = new MouseSettings(); + PowerSupply = new PowerSupplySettings(); Proctoring = new ProctoringSettings(); Security = new SecuritySettings(); Server = new ServerSettings(); diff --git a/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj b/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj index a85f9b3c..347bc3cc 100644 --- a/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj +++ b/SafeExamBrowser.Settings/SafeExamBrowser.Settings.csproj @@ -92,6 +92,7 @@ + diff --git a/SafeExamBrowser.Settings/SystemComponents/PowerSupplySettings.cs b/SafeExamBrowser.Settings/SystemComponents/PowerSupplySettings.cs new file mode 100644 index 00000000..a79f005d --- /dev/null +++ b/SafeExamBrowser.Settings/SystemComponents/PowerSupplySettings.cs @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 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; + +namespace SafeExamBrowser.Settings.SystemComponents +{ + /// + /// Defines all settings for the power supply system component. + /// + [Serializable] + public class PowerSupplySettings + { + /// + /// The threshold below which the charge of the power supply is to be considered critical. + /// + public double ChargeThresholdCritical { get; set; } + + /// + /// The threshold below which the charge of the power supply is to be considered low. + /// + public double ChargeThresholdLow { get; set; } + } +} diff --git a/SafeExamBrowser.SystemComponents/PowerSupply/PowerSupply.cs b/SafeExamBrowser.SystemComponents/PowerSupply/PowerSupply.cs index c6242498..3f3264bc 100644 --- a/SafeExamBrowser.SystemComponents/PowerSupply/PowerSupply.cs +++ b/SafeExamBrowser.SystemComponents/PowerSupply/PowerSupply.cs @@ -9,6 +9,7 @@ using System; using System.Timers; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.Settings.SystemComponents; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply.Events; using PowerLineStatus = System.Windows.Forms.PowerLineStatus; @@ -18,15 +19,20 @@ namespace SafeExamBrowser.SystemComponents.PowerSupply { public class PowerSupply : IPowerSupply { + private readonly ILogger logger; + private readonly PowerSupplySettings settings; + private DateTime lastStatusLog; - private ILogger logger; private Timer timer; + private double critical; + private double low; public event StatusChangedEventHandler StatusChanged; - public PowerSupply(ILogger logger) + public PowerSupply(ILogger logger, PowerSupplySettings settings) { this.logger = logger; + this.settings = settings; } public IPowerSupplyStatus GetStatus() @@ -37,7 +43,7 @@ namespace SafeExamBrowser.SystemComponents.PowerSupply var status = new PowerSupplyStatus(); status.BatteryCharge = charge; - status.BatteryChargeStatus = charge <= 0.2 ? (charge <= 0.1 ? BatteryChargeStatus.Critical : BatteryChargeStatus.Low) : BatteryChargeStatus.Okay; + status.BatteryChargeStatus = charge <= low ? (charge <= critical ? BatteryChargeStatus.Critical : BatteryChargeStatus.Low) : BatteryChargeStatus.Okay; status.BatteryTimeRemaining = new TimeSpan(hours, minutes, 0); status.IsOnline = SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online; @@ -54,12 +60,15 @@ namespace SafeExamBrowser.SystemComponents.PowerSupply { const int TWO_SECONDS = 2000; + critical = SanitizeThreshold(settings.ChargeThresholdCritical); + low = SanitizeThreshold(settings.ChargeThresholdLow); + timer = new Timer(TWO_SECONDS); timer.Elapsed += Timer_Elapsed; timer.AutoReset = true; timer.Start(); - logger.Info("Started monitoring the power supply."); + logger.Info($"Started monitoring the power supply (battery charge thresholds: low = {low * 100}%, critical = {critical * 100}%)."); } public void Terminate() @@ -71,6 +80,11 @@ namespace SafeExamBrowser.SystemComponents.PowerSupply } } + private double SanitizeThreshold(double value) + { + return value < 0 ? 0 : (value > 1 ? 1 : value); + } + private void Timer_Elapsed(object sender, ElapsedEventArgs e) { StatusChanged?.Invoke(GetStatus()); diff --git a/SebWindowsConfig/SEBSettings.cs b/SebWindowsConfig/SEBSettings.cs index 92d751a9..3f6957f9 100644 --- a/SebWindowsConfig/SEBSettings.cs +++ b/SebWindowsConfig/SEBSettings.cs @@ -134,6 +134,9 @@ namespace SebWindowsConfig public const string KeyAudioVolumeLevel = "audioVolumeLevel"; public const string KeyAudioSetVolumeLevel = "audioSetVolumeLevel"; + public const string KeyBatteryChargeThresholdCritical = "batteryChargeThresholdCritical"; + public const string KeyBatteryChargeThresholdLow = "batteryChargeThresholdLow"; + //Touch optimized settings public const String KeyBrowserScreenKeyboard = "browserScreenKeyboard"; @@ -655,6 +658,8 @@ namespace SebWindowsConfig SEBSettings.settingsDefault.Add(SEBSettings.KeyAudioVolumeLevel, 25); SEBSettings.settingsDefault.Add(SEBSettings.KeyAudioSetVolumeLevel, false); SEBSettings.settingsDefault.Add(SEBSettings.KeyAllowDeveloperConsole, false); + SEBSettings.settingsDefault.Add(SEBSettings.KeyBatteryChargeThresholdCritical, 0.1); + SEBSettings.settingsDefault.Add(SEBSettings.KeyBatteryChargeThresholdLow, 0.2); //Touch Settings SEBSettings.settingsDefault.Add(SEBSettings.KeyBrowserScreenKeyboard, false);