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