diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs index 0782e18e..8175c343 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs @@ -15,6 +15,7 @@ using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -28,6 +29,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations private Mock actionCenter; private List activators; private ActionCenterSettings actionCenterSettings; + private Mock audio; private Mock logger; private TaskbarSettings taskbarSettings; private Mock terminationActivator; @@ -37,7 +39,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations private Mock logInfo; private Mock logController; // TODO - //private Mock> audio; //private Mock> powerSupply; //private Mock> wirelessNetwork; private Mock systemInfo; @@ -53,6 +54,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations actionCenter = new Mock(); activators = new List(); actionCenterSettings = new ActionCenterSettings(); + audio = new Mock(); logger = new Mock(); aboutInfo = new Mock(); aboutController = new Mock(); @@ -60,7 +62,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations logInfo = new Mock(); logController = new Mock(); // TODO - //audio = new Mock>(); //powerSupply = new Mock>(); //wirelessNetwork = new Mock>(); systemInfo = new Mock(); @@ -76,6 +77,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations actionCenter.Object, activators, actionCenterSettings, + audio.Object, logger.Object, aboutInfo.Object, aboutController.Object, @@ -196,7 +198,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations taskbarSettings.ShowWirelessNetwork = true; systemInfo.SetupGet(s => s.HasBattery).Returns(true); - uiFactory.Setup(f => f.CreateAudioControl(It.IsAny())).Returns(new Mock().Object); + 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())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny())).Returns(new Mock().Object); @@ -225,7 +227,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations taskbarSettings.ShowWirelessNetwork = false; systemInfo.SetupGet(s => s.HasBattery).Returns(false); - uiFactory.Setup(f => f.CreateAudioControl(It.IsAny())).Returns(new Mock().Object); + 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())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny())).Returns(new Mock().Object); diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index a2293e21..60b66e6f 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -39,7 +39,9 @@ using SafeExamBrowser.Monitoring.Mouse; using SafeExamBrowser.Monitoring.Processes; using SafeExamBrowser.Monitoring.Windows; using SafeExamBrowser.SystemComponents; +using SafeExamBrowser.SystemComponents.Audio; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.MessageBox; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -270,6 +272,7 @@ namespace SafeExamBrowser.Client actionCenter, activators, configuration.Settings.ActionCenter, + audio, logger, aboutInfo, aboutController, @@ -277,7 +280,6 @@ namespace SafeExamBrowser.Client logInfo, logController, // TODO - //audio, //powerSupply, //wirelessNetwork, systemInfo, diff --git a/SafeExamBrowser.Client/Operations/ShellOperation.cs b/SafeExamBrowser.Client/Operations/ShellOperation.cs index 3aaa91bf..7c33141a 100644 --- a/SafeExamBrowser.Client/Operations/ShellOperation.cs +++ b/SafeExamBrowser.Client/Operations/ShellOperation.cs @@ -14,6 +14,7 @@ using SafeExamBrowser.Core.Contracts.OperationModel.Events; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -26,13 +27,13 @@ namespace SafeExamBrowser.Client.Operations private IActionCenter actionCenter; private IEnumerable activators; private ActionCenterSettings actionCenterSettings; + private IAudio audio; private ILogger logger; private INotificationInfo aboutInfo; private INotificationController aboutController; private IKeyboard keyboard; private INotificationInfo logInfo; private INotificationController logController; - // TODO private ISystemComponent audio; // TODO private ISystemComponent powerSupply; // TODO private ISystemComponent wirelessNetwork; private ISystemInfo systemInfo; @@ -49,13 +50,13 @@ namespace SafeExamBrowser.Client.Operations IActionCenter actionCenter, IEnumerable activators, ActionCenterSettings actionCenterSettings, + IAudio audio, ILogger logger, INotificationInfo aboutInfo, INotificationController aboutController, IKeyboard keyboard, INotificationInfo logInfo, INotificationController logController, - // TODO ISystemComponent audio, // TODO ISystemComponent powerSupply, // TODO ISystemComponent wirelessNetwork, ISystemInfo systemInfo, @@ -70,11 +71,11 @@ namespace SafeExamBrowser.Client.Operations this.actionCenter = actionCenter; this.activators = activators; this.actionCenterSettings = actionCenterSettings; + this.audio = audio; this.keyboard = keyboard; this.logger = logger; this.logInfo = logInfo; this.logController = logController; - // TODO this.audio = audio; // TODO this.powerSupply = powerSupply; this.systemInfo = systemInfo; this.taskbarSettings = taskbarSettings; @@ -168,9 +169,9 @@ namespace SafeExamBrowser.Client.Operations private void InitializeSystemComponents() { - // TODO - //audio.Initialize(); + audio.Initialize(); keyboard.Initialize(); + // TODO //powerSupply.Initialize(); //wirelessNetwork.Initialize(); } @@ -201,10 +202,7 @@ namespace SafeExamBrowser.Client.Operations { if (actionCenterSettings.ShowAudio) { - var control = uiFactory.CreateAudioControl(Location.ActionCenter); - - // TODO audio.Register(control); - actionCenter.AddSystemControl(control); + actionCenter.AddSystemControl(uiFactory.CreateAudioControl(audio, Location.ActionCenter)); } } @@ -212,10 +210,7 @@ namespace SafeExamBrowser.Client.Operations { if (taskbarSettings.ShowAudio) { - var control = uiFactory.CreateAudioControl(Location.Taskbar); - - // TODO audio.Register(control); - taskbar.AddSystemControl(control); + taskbar.AddSystemControl(uiFactory.CreateAudioControl(audio, Location.Taskbar)); } } @@ -332,11 +327,11 @@ namespace SafeExamBrowser.Client.Operations private void TerminateSystemComponents() { + audio.Terminate(); + keyboard.Terminate(); // TODO - //audio.Terminate(); //powerSupply.Terminate(); //wirelessNetwork.Terminate(); - keyboard.Terminate(); } } } diff --git a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/AudioMuteRequestedEventHandler.cs b/SafeExamBrowser.SystemComponents.Contracts/Audio/Events/AudioVolumeChangedEventHandler.cs similarity index 60% rename from SafeExamBrowser.UserInterface.Contracts/Shell/Events/AudioMuteRequestedEventHandler.cs rename to SafeExamBrowser.SystemComponents.Contracts/Audio/Events/AudioVolumeChangedEventHandler.cs index b76d7ee1..ebd4f373 100644 --- a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/AudioMuteRequestedEventHandler.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/Audio/Events/AudioVolumeChangedEventHandler.cs @@ -6,10 +6,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -namespace SafeExamBrowser.UserInterface.Contracts.Shell.Events +namespace SafeExamBrowser.SystemComponents.Contracts.Audio.Events { /// - /// Indicates that the user would like to change the audio mute status to the given value. + /// Indicates that the volume of the system audio component has changed. /// - public delegate void AudioMuteRequestedEventHandler(bool mute); + public delegate void AudioVolumeChangedEventHandler(double volume, bool muted); } diff --git a/SafeExamBrowser.SystemComponents.Contracts/Audio/IAudio.cs b/SafeExamBrowser.SystemComponents.Contracts/Audio/IAudio.cs new file mode 100644 index 00000000..360c9de4 --- /dev/null +++ b/SafeExamBrowser.SystemComponents.Contracts/Audio/IAudio.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 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 SafeExamBrowser.SystemComponents.Contracts.Audio.Events; + +namespace SafeExamBrowser.SystemComponents.Contracts.Audio +{ + /// + /// Defines the functionality of the audio system component. + /// + public interface IAudio : ISystemComponent + { + /// + /// The full name of the audio device, or an empty string if not available. + /// + string DeviceFullName { get; } + + /// + /// The short audio device name, or an empty string if not available. + /// + string DeviceShortName { get; } + + /// + /// Indicates whether an audio output device is available. + /// + bool HasOutputDevice { get; } + + /// + /// Indicates whether the audio output is currently muted. + /// + bool OutputMuted { get; } + + /// + /// The current audio output volume. + /// + double OutputVolume { get; } + + /// + /// Fired when the volume of the audio device has changed. + /// + event AudioVolumeChangedEventHandler VolumeChanged; + + /// + /// Mutes the currently active audio device. + /// + void Mute(); + + /// + /// Unmutes the currently active audio device. + /// + void Unmute(); + + /// + /// Sets the volume of the currently active audio device to the given value. + /// + void SetVolume(double value); + } +} diff --git a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj index a43f50e9..ecf65f0c 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj +++ b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj @@ -53,6 +53,8 @@ + + diff --git a/SafeExamBrowser.SystemComponents/Audio.cs b/SafeExamBrowser.SystemComponents/Audio/Audio.cs similarity index 59% rename from SafeExamBrowser.SystemComponents/Audio.cs rename to SafeExamBrowser.SystemComponents/Audio/Audio.cs index 0ec97e74..d99713fc 100644 --- a/SafeExamBrowser.SystemComponents/Audio.cs +++ b/SafeExamBrowser.SystemComponents/Audio/Audio.cs @@ -12,24 +12,33 @@ using NAudio.CoreAudioApi; using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; +using SafeExamBrowser.SystemComponents.Contracts.Audio.Events; -namespace SafeExamBrowser.SystemComponents +namespace SafeExamBrowser.SystemComponents.Audio { - public class Audio// TODO : ISystemComponent + public class Audio : IAudio { private readonly object @lock = new object(); private AudioSettings settings; private MMDevice audioDevice; + private string audioDeviceFullName; private string audioDeviceShortName; - // TODOprivate List controls; private float originalVolume; private ILogger logger; private IText text; + public string DeviceFullName => audioDeviceFullName ?? string.Empty; + public string DeviceShortName => audioDeviceShortName ?? string.Empty; + public bool HasOutputDevice => audioDevice != default(MMDevice); + public bool OutputMuted => audioDevice?.AudioEndpointVolume.Mute == true; + public double OutputVolume => audioDevice?.AudioEndpointVolume.MasterVolumeLevelScalar ?? 0; + + public event AudioVolumeChangedEventHandler VolumeChanged; + public Audio(AudioSettings settings, ILogger logger, IText text) { - // TODOthis.controls = new List(); this.settings = settings; this.logger = logger; this.text = text; @@ -48,19 +57,29 @@ namespace SafeExamBrowser.SystemComponents } } - // TODO - //public void Register(ISystemAudioControl control) - //{ - // control.MuteRequested += Control_MuteRequested; - // control.VolumeSelected += Control_VolumeSelected; + public void Mute() + { + if (audioDevice != default(MMDevice)) + { + audioDevice.AudioEndpointVolume.Mute = true; + } + } - // lock (@lock) - // { - // controls.Add(control); - // } + public void Unmute() + { + if (audioDevice != default(MMDevice)) + { + audioDevice.AudioEndpointVolume.Mute = false; + } + } - // UpdateControls(); - //} + public void SetVolume(double value) + { + if (audioDevice != default(MMDevice)) + { + audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar = (float) value; + } + } public void Terminate() { @@ -69,12 +88,6 @@ namespace SafeExamBrowser.SystemComponents RevertSettings(); FinalizeAudioDevice(); } - - // TODO - //foreach (var control in controls) - //{ - // control.Close(); - //} } private bool TryLoadAudioDevice() @@ -98,6 +111,7 @@ namespace SafeExamBrowser.SystemComponents { logger.Info($"Found '{audioDevice}' to be the active audio device."); audioDevice.AudioEndpointVolume.OnVolumeNotification += AudioEndpointVolume_OnVolumeNotification; + audioDeviceFullName = audioDevice.FriendlyName; audioDeviceShortName = audioDevice.FriendlyName.Length > 25 ? audioDevice.FriendlyName.Split(' ').First() : audioDevice.FriendlyName; logger.Info("Started monitoring the audio device."); } @@ -145,75 +159,9 @@ namespace SafeExamBrowser.SystemComponents { lock (@lock) { - var info = BuildInfoText(data.MasterVolume, data.Muted); - logger.Debug($"Volume is set to {data.MasterVolume * 100}%, audio device is {(data.Muted ? "muted" : "not muted")}."); - - // TODO - //foreach (var control in controls) - //{ - // control.OutputDeviceMuted = data.Muted; - // control.OutputDeviceVolume = data.MasterVolume; - // control.SetInformation(info); - //} + VolumeChanged?.Invoke(data.MasterVolume, data.Muted); } } - - private void Control_MuteRequested(bool mute) - { - audioDevice.AudioEndpointVolume.Mute = mute; - } - - private void Control_VolumeSelected(double volume) - { - audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar = (float) volume; - } - - private void UpdateControls() - { - lock (@lock) - { - try - { - if (audioDevice != default(MMDevice)) - { - var info = BuildInfoText(audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar, audioDevice.AudioEndpointVolume.Mute); - - // TODO - //foreach (var control in controls) - //{ - // control.HasOutputDevice = true; - // control.OutputDeviceMuted = audioDevice.AudioEndpointVolume.Mute; - // control.OutputDeviceName = audioDevice.FriendlyName; - // control.OutputDeviceVolume = audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar; - // control.SetInformation(info); - //} - } - else - { - // TODO - //foreach (var control in controls) - //{ - // control.HasOutputDevice = false; - // control.SetInformation(text.Get(TextKey.SystemControl_AudioDeviceNotFound)); - //} - } - } - catch (Exception e) - { - logger.Error("Failed to update audio device status!", e); - } - } - } - - private string BuildInfoText(float volume, bool muted) - { - var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo); - - info = info.Replace("%%NAME%%", audioDeviceShortName); - info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100))); - - return info; - } } } diff --git a/SafeExamBrowser.SystemComponents/Keyboard.cs b/SafeExamBrowser.SystemComponents/Keyboard/Keyboard.cs similarity index 98% rename from SafeExamBrowser.SystemComponents/Keyboard.cs rename to SafeExamBrowser.SystemComponents/Keyboard/Keyboard.cs index fec56ef9..3e4ff237 100644 --- a/SafeExamBrowser.SystemComponents/Keyboard.cs +++ b/SafeExamBrowser.SystemComponents/Keyboard/Keyboard.cs @@ -16,7 +16,7 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.SystemComponents.Contracts.Keyboard.Events; -namespace SafeExamBrowser.SystemComponents +namespace SafeExamBrowser.SystemComponents.Keyboard { public class Keyboard : IKeyboard { diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs b/SafeExamBrowser.SystemComponents/Keyboard/KeyboardLayout.cs similarity index 93% rename from SafeExamBrowser.SystemComponents/KeyboardLayout.cs rename to SafeExamBrowser.SystemComponents/Keyboard/KeyboardLayout.cs index 155c04a4..59d5bada 100644 --- a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs +++ b/SafeExamBrowser.SystemComponents/Keyboard/KeyboardLayout.cs @@ -10,7 +10,7 @@ using System; using System.Globalization; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; -namespace SafeExamBrowser.SystemComponents +namespace SafeExamBrowser.SystemComponents.Keyboard { internal class KeyboardLayout : IKeyboardLayout { diff --git a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj index d1397e34..bc698bd5 100644 --- a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj +++ b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj @@ -62,9 +62,9 @@ - - - + + + diff --git a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs index 8db9d949..323f8dd2 100644 --- a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs @@ -12,6 +12,7 @@ using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts.Browser; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -37,7 +38,7 @@ namespace SafeExamBrowser.UserInterface.Contracts /// /// Creates a system control which allows to change the audio settings of the computer. /// - ISystemAudioControl CreateAudioControl(Location location); + ISystemControl CreateAudioControl(IAudio audio, Location location); /// /// Creates a new browser window loaded with the given browser control and settings. diff --git a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj index fea91ce6..4bb990a9 100644 --- a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj +++ b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj @@ -67,8 +67,6 @@ - - @@ -76,7 +74,6 @@ - diff --git a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/AudioVolumeSelectedEventHandler.cs b/SafeExamBrowser.UserInterface.Contracts/Shell/Events/AudioVolumeSelectedEventHandler.cs deleted file mode 100644 index 10f53188..00000000 --- a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/AudioVolumeSelectedEventHandler.cs +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2019 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.UserInterface.Contracts.Shell.Events -{ - /// - /// Indicates that the user would like to set the audio volume to the given value, where 0.0 is the lowest and 1.0 the highest - /// possible value. - /// - public delegate void AudioVolumeSelectedEventHandler(double volume); -} diff --git a/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemAudioControl.cs b/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemAudioControl.cs deleted file mode 100644 index 695b977a..00000000 --- a/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemAudioControl.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019 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 SafeExamBrowser.UserInterface.Contracts.Shell.Events; - -namespace SafeExamBrowser.UserInterface.Contracts.Shell -{ - /// - /// The control of the audio system component. - /// - public interface ISystemAudioControl : ISystemControl - { - /// - /// Defines whether the computer has an audio output device. - /// - bool HasOutputDevice { set; } - - /// - /// Indicates whether the current output device is muted. - /// - bool OutputDeviceMuted { set; } - - /// - /// Shows the name of the currently active audio output device. - /// - string OutputDeviceName { set; } - - /// - /// Shows the current audio output volume, where 0.0 is the lowest and 1.0 the highest possible value. - /// - double OutputDeviceVolume { set; } - - /// - /// Event fired when the user requests to mute the current output device. - /// - event AudioMuteRequestedEventHandler MuteRequested; - - /// - /// Event fired when the user requests to set the volume of the current output device. - /// - event AudioVolumeSelectedEventHandler VolumeSelected; - } -} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml index e34fdc78..0e454563 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml @@ -37,7 +37,7 @@ - + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml.cs index a9d97a97..0f9b688d 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterAudioControl.xaml.cs @@ -14,123 +14,80 @@ using System.Windows.Controls.Primitives; using System.Windows.Media; using System.Windows.Threading; using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; using SafeExamBrowser.UserInterface.Shared.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls { - public partial class ActionCenterAudioControl : UserControl, ISystemAudioControl + public partial class ActionCenterAudioControl : UserControl, ISystemControl { + private readonly IAudio audio; private readonly IText text; private bool muted; private XamlIconResource MutedIcon; private XamlIconResource NoDeviceIcon; - public event AudioMuteRequestedEventHandler MuteRequested; - public event AudioVolumeSelectedEventHandler VolumeSelected; - - public ActionCenterAudioControl(IText text) + public ActionCenterAudioControl(IAudio audio, IText text) { + this.audio = audio; this.text = text; InitializeComponent(); InitializeAudioControl(); } - public bool HasOutputDevice - { - set - { - Dispatcher.InvokeAsync(() => - { - Button.IsEnabled = value; - - if (!value) - { - TaskbarIcon.Content = IconResourceLoader.Load(NoDeviceIcon); - } - }); - } - } - - public bool OutputDeviceMuted - { - set - { - Dispatcher.InvokeAsync(() => - { - muted = value; - - if (value) - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); - PopupIcon.Content = IconResourceLoader.Load(MutedIcon); - TaskbarIcon.Content = IconResourceLoader.Load(MutedIcon); - } - else - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); - TaskbarIcon.Content = LoadIcon(Volume.Value / 100); - } - }); - } - } - - public string OutputDeviceName - { - set - { - Dispatcher.InvokeAsync(() => AudioDeviceName.Text = value); - } - } - - public double OutputDeviceVolume - { - set - { - Dispatcher.InvokeAsync(() => - { - Volume.ValueChanged -= Volume_ValueChanged; - Volume.Value = Math.Round(value * 100); - Volume.ValueChanged += Volume_ValueChanged; - - if (!muted) - { - PopupIcon.Content = LoadIcon(value); - TaskbarIcon.Content = LoadIcon(value); - } - }); - } - } - public void Close() { Popup.IsOpen = false; } - public void SetInformation(string text) - { - Dispatcher.InvokeAsync(() => - { - Button.ToolTip = text; - Text.Text = text; - }); - } - private void InitializeAudioControl() { var originalBrush = Grid.Background; + audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); - MuteButton.Click += (o, args) => MuteRequested?.Invoke(!muted); + MuteButton.Click += MuteButton_Click; MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml")); NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_NoDevice.xaml")); 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; Volume.ValueChanged += Volume_ValueChanged; + + if (audio.HasOutputDevice) + { + AudioDeviceName.Text = audio.DeviceFullName; + Button.IsEnabled = true; + UpdateVolume(audio.OutputVolume, audio.OutputMuted); + } + else + { + AudioDeviceName.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + ButtonIcon.Content = IconResourceLoader.Load(NoDeviceIcon); + Text.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + } + } + + private void Audio_VolumeChanged(double volume, bool muted) + { + Dispatcher.InvokeAsync(() => UpdateVolume(volume, muted)); + } + + private void MuteButton_Click(object sender, RoutedEventArgs e) + { + if (muted) + { + audio.Unmute(); + } + else + { + audio.Mute(); + } } private void Volume_DragStarted(object sender, DragStartedEventArgs e) @@ -140,13 +97,49 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls private void Volume_DragCompleted(object sender, DragCompletedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); Volume.ValueChanged += Volume_ValueChanged; } private void Volume_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); + } + + private void UpdateVolume(double volume, bool muted) + { + var info = BuildInfoText(volume, muted); + + this.muted = muted; + + Button.ToolTip = info; + Text.Text = info; + Volume.ValueChanged -= Volume_ValueChanged; + Volume.Value = Math.Round(volume * 100); + Volume.ValueChanged += Volume_ValueChanged; + + if (muted) + { + ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + PopupIcon.Content = IconResourceLoader.Load(MutedIcon); + } + else + { + ButtonIcon.Content = LoadIcon(volume); + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + PopupIcon.Content = LoadIcon(volume); + } + } + + private string BuildInfoText(double volume, bool muted) + { + var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo); + + info = info.Replace("%%NAME%%", audio.DeviceShortName); + info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100))); + + return info; } private UIElement LoadIcon(double volume) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml index ae299a64..3d26dcee 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml @@ -33,7 +33,7 @@ diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml.cs index feb9fd18..321d6e7d 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarAudioControl.xaml.cs @@ -13,113 +13,42 @@ using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; using SafeExamBrowser.UserInterface.Shared.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls { - public partial class TaskbarAudioControl : UserControl, ISystemAudioControl + public partial class TaskbarAudioControl : UserControl, ISystemControl { + private readonly IAudio audio; private readonly IText text; private bool muted; private XamlIconResource MutedIcon; private XamlIconResource NoDeviceIcon; - public event AudioMuteRequestedEventHandler MuteRequested; - public event AudioVolumeSelectedEventHandler VolumeSelected; - - public TaskbarAudioControl(IText text) + public TaskbarAudioControl(IAudio audio, IText text) { + this.audio = audio; this.text = text; InitializeComponent(); InitializeAudioControl(); } - public bool HasOutputDevice - { - set - { - Dispatcher.InvokeAsync(() => - { - Button.IsEnabled = value; - - if (!value) - { - TaskbarIcon.Content = IconResourceLoader.Load(NoDeviceIcon); - } - }); - } - } - - public bool OutputDeviceMuted - { - set - { - Dispatcher.InvokeAsync(() => - { - muted = value; - - if (value) - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); - PopupIcon.Content = IconResourceLoader.Load(MutedIcon); - TaskbarIcon.Content = IconResourceLoader.Load(MutedIcon); - } - else - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); - TaskbarIcon.Content = LoadIcon(Volume.Value / 100); - } - }); - } - } - - public string OutputDeviceName - { - set - { - Dispatcher.InvokeAsync(() => AudioDeviceName.Text = value); - } - } - - public double OutputDeviceVolume - { - set - { - Dispatcher.InvokeAsync(() => - { - Volume.ValueChanged -= Volume_ValueChanged; - Volume.Value = Math.Round(value * 100); - Volume.ValueChanged += Volume_ValueChanged; - - if (!muted) - { - PopupIcon.Content = LoadIcon(value); - TaskbarIcon.Content = LoadIcon(value); - } - }); - } - } - public void Close() { Popup.IsOpen = false; } - public void SetInformation(string text) - { - Dispatcher.InvokeAsync(() => Button.ToolTip = text); - } - private void InitializeAudioControl() { var originalBrush = Button.Background; + audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); - MuteButton.Click += (o, args) => MuteRequested?.Invoke(!muted); + MuteButton.Click += MuteButton_Click; MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml")); NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_NoDevice.xaml")); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); @@ -136,6 +65,37 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls Background = originalBrush; Button.Background = originalBrush; }; + + if (audio.HasOutputDevice) + { + AudioDeviceName.Text = audio.DeviceFullName; + Button.IsEnabled = true; + UpdateVolume(audio.OutputVolume, audio.OutputMuted); + } + else + { + AudioDeviceName.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + ButtonIcon.Content = IconResourceLoader.Load(NoDeviceIcon); + } + } + + private void Audio_VolumeChanged(double volume, bool muted) + { + Dispatcher.InvokeAsync(() => UpdateVolume(volume, muted)); + } + + private void MuteButton_Click(object sender, RoutedEventArgs e) + { + if (muted) + { + audio.Unmute(); + } + else + { + audio.Mute(); + } } private void Volume_DragStarted(object sender, DragStartedEventArgs e) @@ -145,13 +105,48 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls private void Volume_DragCompleted(object sender, DragCompletedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); Volume.ValueChanged += Volume_ValueChanged; } private void Volume_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); + } + + private void UpdateVolume(double volume, bool muted) + { + var info = BuildInfoText(volume, muted); + + this.muted = muted; + + Button.ToolTip = info; + Volume.ValueChanged -= Volume_ValueChanged; + Volume.Value = Math.Round(volume * 100); + Volume.ValueChanged += Volume_ValueChanged; + + if (muted) + { + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + PopupIcon.Content = IconResourceLoader.Load(MutedIcon); + ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); + } + else + { + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + PopupIcon.Content = LoadIcon(volume); + ButtonIcon.Content = LoadIcon(volume); + } + } + + private string BuildInfoText(double volume, bool muted) + { + var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo); + + info = info.Replace("%%NAME%%", audio.DeviceShortName); + info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100))); + + return info; } private UIElement LoadIcon(double volume) diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs index e2d9cbe7..e501cde2 100644 --- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs @@ -16,6 +16,7 @@ using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser; @@ -53,15 +54,15 @@ namespace SafeExamBrowser.UserInterface.Desktop } } - public ISystemAudioControl CreateAudioControl(Location location) + public ISystemControl CreateAudioControl(IAudio audio, Location location) { if (location == Location.ActionCenter) { - return new ActionCenterAudioControl(text); + return new ActionCenterAudioControl(audio, text); } else { - return new TaskbarAudioControl(text); + return new TaskbarAudioControl(audio, text); } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml index d15849b7..bac9251a 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml @@ -41,7 +41,7 @@ - + diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml.cs index 30c3bf74..992128fb 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterAudioControl.xaml.cs @@ -14,123 +14,79 @@ using System.Windows.Controls.Primitives; using System.Windows.Media; using System.Windows.Threading; using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; using SafeExamBrowser.UserInterface.Shared.Utilities; namespace SafeExamBrowser.UserInterface.Mobile.Controls { - public partial class ActionCenterAudioControl : UserControl, ISystemAudioControl + public partial class ActionCenterAudioControl : UserControl, ISystemControl { + private readonly IAudio audio; private readonly IText text; private bool muted; private XamlIconResource MutedIcon; private XamlIconResource NoDeviceIcon; - public event AudioMuteRequestedEventHandler MuteRequested; - public event AudioVolumeSelectedEventHandler VolumeSelected; - - public ActionCenterAudioControl(IText text) + public ActionCenterAudioControl(IAudio audio, IText text) { + this.audio = audio; this.text = text; InitializeComponent(); InitializeAudioControl(); } - public bool HasOutputDevice - { - set - { - Dispatcher.InvokeAsync(() => - { - Button.IsEnabled = value; - - if (!value) - { - TaskbarIcon.Content = IconResourceLoader.Load(NoDeviceIcon); - } - }); - } - } - - public bool OutputDeviceMuted - { - set - { - Dispatcher.InvokeAsync(() => - { - muted = value; - - if (value) - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); - PopupIcon.Content = IconResourceLoader.Load(MutedIcon); - TaskbarIcon.Content = IconResourceLoader.Load(MutedIcon); - } - else - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); - TaskbarIcon.Content = LoadIcon(Volume.Value / 100); - } - }); - } - } - - public string OutputDeviceName - { - set - { - Dispatcher.InvokeAsync(() => AudioDeviceName.Text = value); - } - } - - public double OutputDeviceVolume - { - set - { - Dispatcher.InvokeAsync(() => - { - Volume.ValueChanged -= Volume_ValueChanged; - Volume.Value = Math.Round(value * 100); - Volume.ValueChanged += Volume_ValueChanged; - - if (!muted) - { - PopupIcon.Content = LoadIcon(value); - TaskbarIcon.Content = LoadIcon(value); - } - }); - } - } - public void Close() { Popup.IsOpen = false; } - public void SetInformation(string text) - { - Dispatcher.InvokeAsync(() => - { - Button.ToolTip = text; - Text.Text = text; - }); - } - private void InitializeAudioControl() { var originalBrush = Grid.Background; + audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); - MuteButton.Click += (o, args) => MuteRequested?.Invoke(!muted); - MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml")); - NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_NoDevice.xaml")); + MuteButton.Click += MuteButton_Click; + MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml")); + NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Light_NoDevice.xaml")); 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; Volume.ValueChanged += Volume_ValueChanged; + + if (audio.HasOutputDevice) + { + AudioDeviceName.Text = audio.DeviceFullName; + Button.IsEnabled = true; + UpdateVolume(audio.OutputVolume, audio.OutputMuted); + } + else + { + AudioDeviceName.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + ButtonIcon.Content = IconResourceLoader.Load(NoDeviceIcon); + } + } + + private void Audio_VolumeChanged(double volume, bool muted) + { + Dispatcher.InvokeAsync(() => UpdateVolume(volume, muted)); + } + + private void MuteButton_Click(object sender, RoutedEventArgs e) + { + if (muted) + { + audio.Unmute(); + } + else + { + audio.Mute(); + } } private void Volume_DragStarted(object sender, DragStartedEventArgs e) @@ -140,19 +96,55 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls private void Volume_DragCompleted(object sender, DragCompletedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); Volume.ValueChanged += Volume_ValueChanged; } private void Volume_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); + } + + private void UpdateVolume(double volume, bool muted) + { + var info = BuildInfoText(volume, muted); + + this.muted = muted; + + Button.ToolTip = info; + Text.Text = info; + Volume.ValueChanged -= Volume_ValueChanged; + Volume.Value = Math.Round(volume * 100); + Volume.ValueChanged += Volume_ValueChanged; + + if (muted) + { + ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + PopupIcon.Content = IconResourceLoader.Load(MutedIcon); + } + else + { + ButtonIcon.Content = LoadIcon(volume); + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + PopupIcon.Content = LoadIcon(volume); + } + } + + private string BuildInfoText(double volume, bool muted) + { + var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo); + + info = info.Replace("%%NAME%%", audio.DeviceShortName); + info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100))); + + return info; } private UIElement LoadIcon(double volume) { var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33"); - var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_{icon}.xaml"); + var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Light_{icon}.xaml"); var resource = new XamlIconResource(uri); return IconResourceLoader.Load(resource); diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml index ab59622d..14050e75 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml @@ -37,7 +37,7 @@ diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml.cs index 9465d46b..d6458f55 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarAudioControl.xaml.cs @@ -13,115 +13,44 @@ using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; using SafeExamBrowser.UserInterface.Shared.Utilities; namespace SafeExamBrowser.UserInterface.Mobile.Controls { - public partial class TaskbarAudioControl : UserControl, ISystemAudioControl + public partial class TaskbarAudioControl : UserControl, ISystemControl { + private readonly IAudio audio; private readonly IText text; private bool muted; private XamlIconResource MutedIcon; private XamlIconResource NoDeviceIcon; - public event AudioMuteRequestedEventHandler MuteRequested; - public event AudioVolumeSelectedEventHandler VolumeSelected; - - public TaskbarAudioControl(IText text) + public TaskbarAudioControl(IAudio audio, IText text) { + this.audio = audio; this.text = text; InitializeComponent(); InitializeAudioControl(); } - public bool HasOutputDevice - { - set - { - Dispatcher.InvokeAsync(() => - { - Button.IsEnabled = value; - - if (!value) - { - TaskbarIcon.Content = IconResourceLoader.Load(NoDeviceIcon); - } - }); - } - } - - public bool OutputDeviceMuted - { - set - { - Dispatcher.InvokeAsync(() => - { - muted = value; - - if (value) - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); - PopupIcon.Content = IconResourceLoader.Load(MutedIcon); - TaskbarIcon.Content = IconResourceLoader.Load(MutedIcon); - } - else - { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); - TaskbarIcon.Content = LoadIcon(Volume.Value / 100); - } - }); - } - } - - public string OutputDeviceName - { - set - { - Dispatcher.InvokeAsync(() => AudioDeviceName.Text = value); - } - } - - public double OutputDeviceVolume - { - set - { - Dispatcher.InvokeAsync(() => - { - Volume.ValueChanged -= Volume_ValueChanged; - Volume.Value = Math.Round(value * 100); - Volume.ValueChanged += Volume_ValueChanged; - - if (!muted) - { - PopupIcon.Content = LoadIcon(value); - TaskbarIcon.Content = LoadIcon(value); - } - }); - } - } - public void Close() { Popup.IsOpen = false; } - public void SetInformation(string text) - { - Dispatcher.InvokeAsync(() => Button.ToolTip = text); - } - private void InitializeAudioControl() { var originalBrush = Button.Background; + audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); - MuteButton.Click += (o, args) => MuteRequested?.Invoke(!muted); - MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml")); - NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_NoDevice.xaml")); + MuteButton.Click += MuteButton_Click; + MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml")); + NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_NoDevice.xaml")); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); Volume.ValueChanged += Volume_ValueChanged; @@ -136,6 +65,37 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls Background = originalBrush; Button.Background = originalBrush; }; + + if (audio.HasOutputDevice) + { + AudioDeviceName.Text = audio.DeviceFullName; + Button.IsEnabled = true; + UpdateVolume(audio.OutputVolume, audio.OutputMuted); + } + else + { + AudioDeviceName.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + Button.IsEnabled = false; + Button.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceNotFound); + ButtonIcon.Content = IconResourceLoader.Load(NoDeviceIcon); + } + } + + private void Audio_VolumeChanged(double volume, bool muted) + { + Dispatcher.InvokeAsync(() => UpdateVolume(volume, muted)); + } + + private void MuteButton_Click(object sender, RoutedEventArgs e) + { + if (muted) + { + audio.Unmute(); + } + else + { + audio.Mute(); + } } private void Volume_DragStarted(object sender, DragStartedEventArgs e) @@ -145,19 +105,54 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls private void Volume_DragCompleted(object sender, DragCompletedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); Volume.ValueChanged += Volume_ValueChanged; } private void Volume_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - VolumeSelected?.Invoke(Volume.Value / 100); + audio.SetVolume(Volume.Value / 100); + } + + private void UpdateVolume(double volume, bool muted) + { + var info = BuildInfoText(volume, muted); + + this.muted = muted; + + Button.ToolTip = info; + Volume.ValueChanged -= Volume_ValueChanged; + Volume.Value = Math.Round(volume * 100); + Volume.ValueChanged += Volume_ValueChanged; + + if (muted) + { + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + PopupIcon.Content = IconResourceLoader.Load(MutedIcon); + ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); + } + else + { + MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + PopupIcon.Content = LoadIcon(volume); + ButtonIcon.Content = LoadIcon(volume); + } + } + + private string BuildInfoText(double volume, bool muted) + { + var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo); + + info = info.Replace("%%NAME%%", audio.DeviceShortName); + info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100))); + + return info; } private UIElement LoadIcon(double volume) { var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33"); - var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_{icon}.xaml"); + var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_{icon}.xaml"); var resource = new XamlIconResource(uri); return IconResourceLoader.Load(resource); diff --git a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs index c9a61493..30acca80 100644 --- a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs @@ -16,6 +16,7 @@ using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Audio; using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser; @@ -53,15 +54,15 @@ namespace SafeExamBrowser.UserInterface.Mobile } } - public ISystemAudioControl CreateAudioControl(Location location) + public ISystemControl CreateAudioControl(IAudio audio, Location location) { if (location == Location.ActionCenter) { - return new ActionCenterAudioControl(text); + return new ActionCenterAudioControl(audio, text); } else { - return new TaskbarAudioControl(text); + return new TaskbarAudioControl(audio, text); } }