Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/Applications/ACATApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,9 @@ private static void InitializeDependencyInjection()

_serviceProvider = services.BuildServiceProvider();

// Make service provider available to Context for extension loading
Context.ServiceProvider = _serviceProvider;
// Resolve Context from DI – this sets Context.ServiceProvider automatically
// so all static Context.AppXXX accessors resolve managers through the container.
_serviceProvider.GetRequiredService<IContext>();

_logger.LogDebug("Dependency injection initialized with ACAT services");
}
Expand Down
5 changes: 3 additions & 2 deletions src/Applications/ACATTalk/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,9 @@ private static void InitializeDependencyInjection()

_serviceProvider = services.BuildServiceProvider();

// Make service provider available to Context for extension loading
Context.ServiceProvider = _serviceProvider;
// Resolve Context from DI – this sets Context.ServiceProvider automatically
// so all static Context.AppXXX accessors resolve managers through the container.
_serviceProvider.GetRequiredService<IContext>();

_logger.LogDebug("Dependency injection initialized with ACAT services");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,57 @@
// Assert
Assert.IsNull(Context.ServiceProvider);
}

[TestMethod]
public void IContext_ResolvedFromServiceProvider_IsNotNull()
{
// Arrange
var services = new ServiceCollection();
services.AddLogging();
services.AddACATServices();
var serviceProvider = services.BuildServiceProvider();

// Act
var context = serviceProvider.GetService<IContext>();

// Assert
Assert.IsNotNull(context);
Assert.IsInstanceOfType(context, typeof(IContext));
}

[TestMethod]
public void IContext_ResolvingSetsStaticServiceProvider()
{
// Arrange
Context.ServiceProvider = null;
var services = new ServiceCollection();
services.AddLogging();
services.AddACATServices();
var serviceProvider = services.BuildServiceProvider();

// Act – resolving IContext should configure Context.ServiceProvider
serviceProvider.GetRequiredService<IContext>();

// Assert
Assert.IsNotNull(Context.ServiceProvider);
Assert.AreSame(serviceProvider, Context.ServiceProvider);

Check failure on line 182 in src/Libraries/ACATCore.Tests.Configuration/ContextDependencyInjectionTests.cs

View workflow job for this annotation

GitHub Actions / Test Results

ACATCore.Tests.Configuration.ContextDependencyInjectionTests ► IContext_ResolvingSetsStaticServiceProvider

Failed test found in: src/TestResults/config-results.trx Error: Assert.AreSame failed.
Raw output
Assert.AreSame failed. 
   at ACATCore.Tests.Configuration.ContextDependencyInjectionTests.IContext_ResolvingSetsStaticServiceProvider() in D:\a\acat\acat\src\Libraries\ACATCore.Tests.Configuration\ContextDependencyInjectionTests.cs:line 182
}

[TestMethod]
public void Context_AndIContext_ResolveSameSingletonInstance()
{
// Arrange
var services = new ServiceCollection();
services.AddLogging();
services.AddACATServices();
var serviceProvider = services.BuildServiceProvider();

// Act
var iContext = serviceProvider.GetRequiredService<IContext>();
var context = serviceProvider.GetRequiredService<Context>();

// Assert – both registrations return the same singleton
Assert.AreSame(iContext, context);
}
}
}
1 change: 1 addition & 0 deletions src/Libraries/ACATCore/ACAT.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@
<Compile Include="PanelManagement\PanelConfig\PanelConfigMap.cs" />
<Compile Include="PanelManagement\PanelConfig\PanelConfigMapEntry.cs" />
<Compile Include="PanelManagement\PanelManager.cs" />
<Compile Include="PanelManagement\IContext.cs" />
<Compile Include="PanelManagement\IPanelManager.cs" />
<Compile Include="PanelManagement\IPanelManagerFactory.cs" />
<Compile Include="PanelManagement\IScannerFactory.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ namespace ACAT.Core.DependencyInjection
/// </remarks>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Registers the <see cref="Context"/> as a singleton and exposes it through
/// <see cref="IContext"/>. The factory sets <see cref="Context.ServiceProvider"/>
/// from the DI container so that all static <c>Context.AppXXX</c> accessor
/// properties resolve managers through the DI container automatically.
/// </summary>
public static IServiceCollection AddContextService(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));

services.AddSingleton<IContext>(provider => new Context(provider));
services.AddSingleton<Context>(provider => (Context)provider.GetRequiredService<IContext>());
return services;
}

// ---------------------------------------------------------------
// Individual module registration methods
// ---------------------------------------------------------------
Expand Down Expand Up @@ -284,6 +299,7 @@ public static IServiceCollection AddACATCoreModules(this IServiceCollection serv
if (services == null) throw new ArgumentNullException(nameof(services));

services
.AddContextService()
.AddACATConfiguration()
.AddActuatorManagement()
.AddAgentManagement()
Expand Down
70 changes: 69 additions & 1 deletion src/Libraries/ACATCore/PanelManagement/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace ACAT.Core.PanelManagement
/// PostInit()
///
/// </summary>
public class Context
public class Context : IContext
{
private static readonly Lazy<AbbreviationsManager> _abbreviationsManager = new Lazy<AbbreviationsManager>(() => AbbreviationsManager.Instance);
private static readonly Lazy<ActuatorManager> _actuatorManager = new Lazy<ActuatorManager>(() => ActuatorManager.Instance);
Expand Down Expand Up @@ -82,6 +82,74 @@ static Context()
// This allows Context.ServiceProvider to be set before managers are created
}

/// <summary>
/// Initializes a new instance of Context for dependency injection.
/// Configures the static <see cref="ServiceProvider"/> from the injected
/// <paramref name="serviceProvider"/> so that all static accessor properties
/// resolve managers through the DI container.
/// </summary>
/// <param name="serviceProvider">The application DI service provider.</param>
public Context(IServiceProvider serviceProvider)
{
if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider));
ServiceProvider = serviceProvider;
}

// ---------------------------------------------------------------
// IContext instance implementation – each property / method
// delegates to the corresponding static member so that consumers
// using the injected IContext get the same behaviour as those
// using the static Context.AppXXX API.
// ---------------------------------------------------------------

AbbreviationsManager IContext.AppAbbreviationsManager => AppAbbreviationsManager;
ActuatorManager IContext.AppActuatorManager => AppActuatorManager;
AgentManager IContext.AppAgentMgr => AppAgentMgr;
AutomationEventManager IContext.AppAutomationEventManger => AppAutomationEventManger;
CommandManager IContext.AppCommandManager => AppCommandManager;
PanelManager IContext.AppPanelManager => AppPanelManager;

bool IContext.AppQuit
{
get => AppQuit;
set => AppQuit = value;
}

SpellCheckManager IContext.AppSpellCheckManager => AppSpellCheckManager;
ThemeManager IContext.AppThemeManager => AppThemeManager;
TTSManager IContext.AppTTSManager => AppTTSManager;

Windows.WindowPosition IContext.AppWindowPosition
{
get => AppWindowPosition;
set => AppWindowPosition = value;
}

WordPredictionManager IContext.AppWordPredictionManager => AppWordPredictionManager;
IEnumerable<String> IContext.ExtensionDirs => ExtensionDirs;

string IContext.KeyboardLayout
{
get => KeyboardLayout;
set => KeyboardLayout = value;
}

bool IContext.RestartKeyboardLayout
{
get => RestartKeyboardLayout;
set => RestartKeyboardLayout = value;
}

bool IContext.ShowTalkWindowOnStartup
{
get => ShowTalkWindowOnStartup;
set => ShowTalkWindowOnStartup = value;
}

TInterface IContext.GetManager<TInterface>() => GetManager<TInterface>();
string IContext.GetInitCompletionStatus() => GetInitCompletionStatus();
bool IContext.IsInitFatal() => IsInitFatal();

/// <summary>
/// Raised when the culture changes
/// </summary>
Expand Down
92 changes: 92 additions & 0 deletions src/Libraries/ACATCore/PanelManagement/IContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2013-2019; 2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
////////////////////////////////////////////////////////////////////////////

using ACAT.Core.AbbreviationsManagement;
using ACAT.Core.ActuatorManagement;
using ACAT.Core.AgentManagement;
using ACAT.Core.CommandManagement;
using ACAT.Core.SpellCheckManagement;
using ACAT.Core.ThemeManagement;
using ACAT.Core.TTSManagement;
using ACAT.Core.Utility;
using ACAT.Core.WordPredictorManagement;
using System;
using System.Collections.Generic;

namespace ACAT.Core.PanelManagement
{
/// <summary>
/// Provides access to ACAT system-wide managers and configuration.
/// Implement this interface when consuming Context via dependency injection;
/// it mirrors the static <see cref="Context"/> API so that callers can
/// switch from <c>Context.AppXXX</c> to an injected <see cref="IContext"/>
/// without changing the property names.
/// </summary>
public interface IContext
{
/// <summary>Gets the Abbreviations Manager.</summary>
AbbreviationsManager AppAbbreviationsManager { get; }

/// <summary>Gets the Actuator Manager.</summary>
ActuatorManager AppActuatorManager { get; }

/// <summary>Gets the Agent Manager.</summary>
AgentManager AppAgentMgr { get; }

/// <summary>Gets the Automation Event Manager.</summary>
AutomationEventManager AppAutomationEventManger { get; }

/// <summary>Gets the Command Manager.</summary>
CommandManager AppCommandManager { get; }

/// <summary>Gets the Panel Manager.</summary>
PanelManager AppPanelManager { get; }

/// <summary>Gets or sets whether the application should quit.</summary>
bool AppQuit { get; set; }

/// <summary>Gets the Spell Check Manager.</summary>
SpellCheckManager AppSpellCheckManager { get; }

/// <summary>Gets the Theme Manager.</summary>
ThemeManager AppThemeManager { get; }

/// <summary>Gets the Text-to-Speech Manager.</summary>
TTSManager AppTTSManager { get; }

/// <summary>Gets or sets the current scanner window position.</summary>
Windows.WindowPosition AppWindowPosition { get; set; }

/// <summary>Gets the Word Prediction Manager.</summary>
WordPredictionManager AppWordPredictionManager { get; }

/// <summary>Gets the list of extension directories.</summary>
IEnumerable<String> ExtensionDirs { get; }

/// <summary>Gets or sets the keyboard layout command name.</summary>
string KeyboardLayout { get; set; }

/// <summary>Gets or sets whether a keyboard-layout change was requested.</summary>
bool RestartKeyboardLayout { get; set; }

/// <summary>Gets or sets whether the talk window should be shown on startup.</summary>
bool ShowTalkWindowOnStartup { get; set; }

/// <summary>
/// Resolves a manager by interface type from the service provider.
/// </summary>
/// <typeparam name="TInterface">The interface type to resolve.</typeparam>
/// <returns>The manager instance, or <c>null</c> if not registered.</returns>
TInterface GetManager<TInterface>() where TInterface : class;

/// <summary>Returns the initialization completion status string.</summary>
string GetInitCompletionStatus();

/// <summary>Returns whether the initialization error was fatal.</summary>
bool IsInitFatal();
}
}
Loading