Skip to content

Commit 859eb74

Browse files
committed
Require enableForegroundService param for MediaElement init
Refactored UseMauiCommunityToolkitMediaElement to require the enableForegroundService parameter, enforcing explicit configuration of Android foreground service support. Added a Roslyn analyzer (MCTME002) to ensure this parameter is always specified, with localized error messages and comprehensive analyzer tests. Updated all usages and resource files to reflect the new method signature and diagnostics.
1 parent eeeba09 commit 859eb74

File tree

8 files changed

+391
-14
lines changed

8 files changed

+391
-14
lines changed

samples/CommunityToolkit.Maui.Sample/MauiProgram.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ public static MauiApp CreateMauiApp()
6969
.UseMauiCommunityToolkitMarkup()
7070
.UseMauiCommunityToolkitCamera()
7171
.UseMauiCommunityToolkitMediaElement(
72+
enableForegroundService: true,
7273
static options =>
7374
{
7475
options.SetDefaultAndroidViewType(AndroidViewType.TextureView);
75-
},
76-
enableForegroundService: true)
76+
})
7777
.ConfigureMauiHandlers(static handlers =>
7878
{
7979
#if IOS || MACCATALYST
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
using CommunityToolkit.Maui.Core;
2+
using CommunityToolkit.Maui.MediaElement.Analyzers;
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.Testing;
5+
using Xunit;
6+
using static CommunityToolkit.Maui.Analyzers.UnitTests.CSharpAnalyzerVerifier<CommunityToolkit.Maui.MediaElement.Analyzers.UseCommunityToolkitMediaElementEnableForegroundServiceAnalyzer>;
7+
8+
namespace CommunityToolkit.Maui.Analyzers.UnitTests;
9+
10+
public class UseCommunityToolkitMediaElementEnableForegroundServiceAnalyzerTests
11+
{
12+
[Fact]
13+
public void UseCommunityToolkitMediaElementEnableForegroundServiceAnalyzerId()
14+
{
15+
Assert.Equal("MCTME002", UseCommunityToolkitMediaElementEnableForegroundServiceAnalyzer.DiagnosticId);
16+
}
17+
18+
[Fact]
19+
public async Task VerifyNoErrorsWhenEnableForegroundServiceIsProvidedAsNamedArgument()
20+
{
21+
const string source =
22+
/* language=C#-test */
23+
//lang=csharp
24+
"""
25+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
26+
{
27+
using Microsoft.Maui.Controls.Hosting;
28+
using Microsoft.Maui.Hosting;
29+
using CommunityToolkit.Maui;
30+
31+
public static class MauiProgram
32+
{
33+
public static MauiApp CreateMauiApp()
34+
{
35+
var builder = MauiApp.CreateBuilder();
36+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
37+
.UseMauiCommunityToolkitMediaElement(enableForegroundService: true)
38+
.ConfigureFonts(fonts =>
39+
{
40+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
41+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
42+
});
43+
44+
return builder.Build();
45+
}
46+
}
47+
}
48+
""";
49+
50+
await VerifyMediaElementToolkitAnalyzer(source);
51+
}
52+
53+
[Fact]
54+
public async Task VerifyNoErrorsWhenEnableForegroundServiceIsProvidedAsPositionalArgument()
55+
{
56+
const string source =
57+
/* language=C#-test */
58+
//lang=csharp
59+
"""
60+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
61+
{
62+
using Microsoft.Maui.Controls.Hosting;
63+
using Microsoft.Maui.Hosting;
64+
using CommunityToolkit.Maui;
65+
66+
public static class MauiProgram
67+
{
68+
public static MauiApp CreateMauiApp()
69+
{
70+
var builder = MauiApp.CreateBuilder();
71+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
72+
.UseMauiCommunityToolkitMediaElement(false)
73+
.ConfigureFonts(fonts =>
74+
{
75+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
76+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
77+
});
78+
79+
return builder.Build();
80+
}
81+
}
82+
}
83+
""";
84+
85+
await VerifyMediaElementToolkitAnalyzer(source);
86+
}
87+
88+
[Fact]
89+
public async Task VerifyNoErrorsWhenEnableForegroundServiceIsProvidedWithOptions()
90+
{
91+
const string source =
92+
/* language=C#-test */
93+
//lang=csharp
94+
"""
95+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
96+
{
97+
using Microsoft.Maui.Controls.Hosting;
98+
using Microsoft.Maui.Hosting;
99+
using CommunityToolkit.Maui;
100+
101+
public static class MauiProgram
102+
{
103+
public static MauiApp CreateMauiApp()
104+
{
105+
var builder = MauiApp.CreateBuilder();
106+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
107+
.UseMauiCommunityToolkitMediaElement(
108+
enableForegroundService: false,
109+
static options => { })
110+
.ConfigureFonts(fonts =>
111+
{
112+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
113+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
114+
});
115+
116+
return builder.Build();
117+
}
118+
}
119+
}
120+
""";
121+
122+
await VerifyMediaElementToolkitAnalyzer(source);
123+
}
124+
125+
[Fact]
126+
public async Task VerifyErrorsWhenOptionsProvidedButEnableForegroundServiceIsMissing()
127+
{
128+
const string source =
129+
/* language=C#-test */
130+
//lang=csharp
131+
"""
132+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
133+
{
134+
using Microsoft.Maui.Controls.Hosting;
135+
using Microsoft.Maui.Hosting;
136+
using CommunityToolkit.Maui;
137+
138+
public static class MauiProgram
139+
{
140+
public static MauiApp CreateMauiApp()
141+
{
142+
var builder = MauiApp.CreateBuilder();
143+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
144+
.UseMauiCommunityToolkitMediaElement(static options => { })
145+
.ConfigureFonts(fonts =>
146+
{
147+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
148+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
149+
});
150+
151+
return builder.Build();
152+
}
153+
}
154+
}
155+
""";
156+
157+
// When options are provided without enableForegroundService, both diagnostics are produced:
158+
// 1. Our analyzer detects the missing enableForegroundService parameter
159+
// 2. The compiler produces CS1660 because lambda is passed where bool is expected
160+
await VerifyMediaElementToolkitAnalyzer(source,
161+
Diagnostic().WithSpan(13, 5, 13, 64).WithSeverity(DiagnosticSeverity.Error),
162+
DiagnosticResult.CompilerError("CS1660").WithSpan(13, 57, 13, 59).WithArguments("lambda expression", "bool"));
163+
}
164+
165+
[Fact]
166+
public async Task VerifyErrorsWhenNoArgumentsProvided()
167+
{
168+
const string source =
169+
/* language=C#-test */
170+
//lang=csharp
171+
"""
172+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
173+
{
174+
using Microsoft.Maui.Controls.Hosting;
175+
using Microsoft.Maui.Hosting;
176+
using CommunityToolkit.Maui;
177+
178+
public static class MauiProgram
179+
{
180+
public static MauiApp CreateMauiApp()
181+
{
182+
var builder = MauiApp.CreateBuilder();
183+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
184+
.UseMauiCommunityToolkitMediaElement()
185+
.ConfigureFonts(fonts =>
186+
{
187+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
188+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
189+
});
190+
191+
return builder.Build();
192+
}
193+
}
194+
}
195+
""";
196+
197+
// When no arguments are provided at all, both diagnostics should be produced:
198+
// 1. Our analyzer detects the missing enableForegroundService parameter
199+
// 2. The compiler produces CS7036 because required parameter 'enableForegroundService' is missing
200+
await VerifyMediaElementToolkitAnalyzer(source,
201+
Diagnostic().WithSpan(13, 6, 13, 41).WithSeverity(DiagnosticSeverity.Error),
202+
DiagnosticResult.CompilerError("CS7036").WithSpan(13, 6, 13, 41).WithArguments("enableForegroundService", "CommunityToolkit.Maui.AppBuilderExtensions.UseMauiCommunityToolkitMediaElement(Microsoft.Maui.Hosting.MauiAppBuilder, bool, System.Action<CommunityToolkit.Maui.Core.MediaElementOptions>?)"));
203+
}
204+
205+
static Task VerifyMediaElementToolkitAnalyzer(string source, params IReadOnlyList<DiagnosticResult> diagnosticResults)
206+
{
207+
return VerifyAnalyzerAsync(
208+
source,
209+
[
210+
typeof(MediaElementOptions) // CommunityToolkit.Maui.MediaElement
211+
],
212+
diagnosticResults);
213+
}
214+
}

src/CommunityToolkit.Maui.Analyzers.UnitTests/UseCommunityToolkitMediaElementInitializationAnalyzerTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using CommunityToolkit.Maui.Core;
1+
using CommunityToolkit.Maui.Core;
22
using CommunityToolkit.Maui.MediaElement.Analyzers;
33
using Microsoft.CodeAnalysis;
44
using Microsoft.CodeAnalysis.Testing;
@@ -34,7 +34,7 @@ public static MauiApp CreateMauiApp()
3434
{
3535
var builder = MauiApp.CreateBuilder();
3636
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
37-
.UseMauiCommunityToolkitMediaElement()
37+
.UseMauiCommunityToolkitMediaElement(enableForegroundService: true)
3838
.ConfigureFonts(fonts =>
3939
{
4040
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
@@ -69,7 +69,7 @@ public static MauiApp CreateMauiApp()
6969
{
7070
var builder = MauiApp.CreateBuilder ();
7171
builder.UseMauiApp<Microsoft.Maui.Controls.Application> ()
72-
.UseMauiCommunityToolkitMediaElement ()
72+
.UseMauiCommunityToolkitMediaElement(enableForegroundService: true)
7373
.ConfigureFonts(fonts =>
7474
{
7575
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
@@ -139,7 +139,7 @@ public static MauiApp CreateMauiApp()
139139
var builder = MauiApp.CreateBuilder();
140140
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
141141
#if ANDROID || IOS
142-
.UseMauiCommunityToolkitMediaElement()
142+
.UseMauiCommunityToolkitMediaElement(enableForegroundService: true)
143143
#endif
144144
.ConfigureFonts(fonts =>
145145
{

src/CommunityToolkit.Maui.MediaElement.Analyzers/Resources.Designer.cs

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/CommunityToolkit.Maui.MediaElement.Analyzers/Resources.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,13 @@
2121
<data name="InitializationErrorTitle" xml:space="preserve">
2222
<value>`.UseMauiCommunityToolkitMediaElement()` Not Found on MauiAppBuilder</value>
2323
</data>
24+
<data name="EnableForegroundServiceErrorTitle" xml:space="preserve">
25+
<value>`enableForegroundService` parameter is required for `.UseMauiCommunityToolkitMediaElement()`</value>
26+
</data>
27+
<data name="EnableForegroundServiceMessageFormat" xml:space="preserve">
28+
<value>`.UseMauiCommunityToolkitMediaElement()` requires the `enableForegroundService` parameter to be explicitly specified</value>
29+
</data>
30+
<data name="EnableForegroundServiceErrorMessage" xml:space="preserve">
31+
<value>The `enableForegroundService` parameter must be provided when calling `.UseMauiCommunityToolkitMediaElement()` to explicitly configure Android foreground service support.</value>
32+
</data>
2433
</root>

0 commit comments

Comments
 (0)