Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions build-tools/automation/azure-pipelines-internal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,8 @@ extends:
- pwsh: ./build.ps1 --target=dotnet-pack --configuration="$(XA.Build.Configuration)" --nugetsource="$(Build.StagingDirectory)\android-packs" --verbosity=diagnostic
displayName: Pack .NET Maui
workingDirectory: $(Build.SourcesDirectory)/maui
env:
NoWarn: CS0618

- task: DotNetCoreCLI@2
displayName: Install MAUI workload packs
Expand Down
2 changes: 2 additions & 0 deletions build-tools/automation/azure-pipelines-public.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,8 @@ stages:
- pwsh: ./build.ps1 --target=dotnet-pack --configuration="$(XA.Build.Configuration)" --nugetsource="$(Build.StagingDirectory)\android-packs" --verbosity=diagnostic
displayName: Pack .NET Maui
workingDirectory: $(Build.SourcesDirectory)/maui
env:
NoWarn: CS0618

- task: DotNetCoreCLI@2
displayName: Install MAUI workload packs
Expand Down
2 changes: 2 additions & 0 deletions build-tools/automation/azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ extends:
- pwsh: ./build.ps1 --target=dotnet-pack --configuration="$(XA.Build.Configuration)" --nugetsource="$(Build.StagingDirectory)\android-packs" --verbosity=diagnostic
displayName: Pack .NET Maui
workingDirectory: $(Build.SourcesDirectory)/maui
env:
NoWarn: CS0618

- task: DotNetCoreCLI@2
displayName: Install MAUI workload packs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -804,13 +804,16 @@ public void ObsoletedOSPlatformAttributeUnneededSupport ()
generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
generator.Context.ContextTypes.Pop ();

// These should use [Obsolete] because they have always been obsolete in all currently supported versions (21+)
// These should use [Obsolete] because they have always been obsolete in all currently supported versions (24+)
Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is a field deprecated since 0!\")]"), writer.ToString ());
Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is a constructor deprecated since empty string!\")]"), writer.ToString ());

// getCount/setCount were deprecated-since 22, which is below MINIMUM_API_LEVEL (24), so they
// should use [Obsolete] rather than [ObsoletedOSPlatform] since they have always been obsolete.
Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"deprecated\")]"), writer.ToString ());

// This should not have a message because the default "deprecated" message isn't useful
Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\")]"), writer.ToString ());
Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android22.0\")]"), writer.ToString ());

// This should use [Obsolete] because the 'deprecated-since' attribute could not be parsed
Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This method has an invalid deprecated-since!\")]"), writer.ToString ());
Expand Down Expand Up @@ -1450,6 +1453,58 @@ public void SupportedOSPlatformConstFields ()
StringAssert.Contains ("[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android30.0\")]", builder.ToString (), "Should contain SupportedOSPlatform!");
}

[Test]
// CodeGenerationOptions.MinimumApiLevel defaults to 24 (matches $(AndroidMinimumDotNetApiLevel)
// in Configuration.props), so there's no sense writing [SupportedOSPlatform] for an API
// available at or below that floor: it's available in every version we support. Only API
// levels above the floor need it.
[TestCase (22, false)]
[TestCase (23, false)]
[TestCase (24, false)]
[TestCase (25, true)]
public void SupportedOSPlatformOmittedAtOrBelowMinimumApiLevel (int apiLevel, bool expectAttribute)
{
var klass = SupportTypeBuilder.CreateClass ("java.code.MyClass", options);
klass.ApiAvailableSince = new AndroidSdkVersion (apiLevel);

generator.Context.ContextTypes.Push (klass);
generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
generator.Context.ContextTypes.Pop ();

var attribute = $"[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android{apiLevel}.0\")]";

if (expectAttribute)
StringAssert.Contains (attribute, builder.ToString (), $"Should contain SupportedOSPlatform for android{apiLevel}!");
else
StringAssert.DoesNotContain (attribute, builder.ToString (), $"Should NOT contain SupportedOSPlatform for android{apiLevel}!");
}

[Test]
// Confirms MinimumApiLevel is actually wired through, not just defaulted: overriding it to a
// non-default value moves the floor below which [SupportedOSPlatform] is omitted.
[TestCase (21, 22, true)]
[TestCase (21, 21, false)]
[TestCase (30, 25, false)]
[TestCase (30, 31, true)]
public void SupportedOSPlatformRespectsMinimumApiLevelOverride (int minimumApiLevel, int apiLevel, bool expectAttribute)
{
options.MinimumApiLevel = minimumApiLevel;

var klass = SupportTypeBuilder.CreateClass ("java.code.MyClass", options);
klass.ApiAvailableSince = new AndroidSdkVersion (apiLevel);

generator.Context.ContextTypes.Push (klass);
generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
generator.Context.ContextTypes.Pop ();

var attribute = $"[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android{apiLevel}.0\")]";

if (expectAttribute)
StringAssert.Contains (attribute, builder.ToString (), $"Should contain SupportedOSPlatform for android{apiLevel} with MinimumApiLevel={minimumApiLevel}!");
else
StringAssert.DoesNotContain (attribute, builder.ToString (), $"Should NOT contain SupportedOSPlatform for android{apiLevel} with MinimumApiLevel={minimumApiLevel}!");
}

[Test]
public void UnsupportedOSPlatform ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public SymbolTable SymbolTable {
public string AssemblyName { get; set; }
public bool UseShortFileNames { get; set; }
public int ProductVersion { get; set; }
public int MinimumApiLevel { get; set; } = 24;
public bool SupportInterfaceConstants { get; set; }
public bool SupportDefaultInterfaceMethods { get; set; }
public bool SupportNestedInterfaceTypes { get; set; }
Expand Down
1 change: 1 addition & 0 deletions external/Java.Interop/tools/generator/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve
IgnoreNonPublicType = true,
UseShortFileNames = options.UseShortFileNames,
ProductVersion = options.ProductVersion,
MinimumApiLevel = options.MinimumApiLevel,
SupportInterfaceConstants = options.SupportInterfaceConstants,
SupportDefaultInterfaceMethods = options.SupportDefaultInterfaceMethods,
SupportNestedInterfaceTypes = options.SupportNestedInterfaceTypes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public CodeGeneratorOptions ()
public bool PreserveEnums {get; set;}
public bool UseShortFileNames {get; set;}
public int ProductVersion { get; set; }
public int MinimumApiLevel {get; set;} = 24;
public string MappingReportFile { get; set; }
public bool OnlyRunApiXmlAdjuster { get; set; }
public string ApiXmlAdjusterOutput { get; set; }
Expand Down Expand Up @@ -128,6 +129,9 @@ public static CodeGeneratorOptions Parse (string[] args)
{ "product-version=",
"Xamarin.Android Major Product Version",
(int? v) => opts.ProductVersion = v.HasValue ? v.Value : 0 },
{ "minimum-api-level=",
"Minimum supported Android API {LEVEL}. APIs available at or below this level never need a [SupportedOSPlatform] attribute since they're always present. Defaults to 24.",
(int v) => opts.MinimumApiLevel = v },
Comment thread
simonrozsival marked this conversation as resolved.
{ "v:",
"Logging Verbosity",
(int? v) => Report.Verbosity = v.HasValue ? v.Value : (Report.Verbosity ?? 0) + 1 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ namespace generator.SourceWriters
{
public static class SourceWriterExtensions
{
const int MINIMUM_API_LEVEL = 21;

public static void AddField (TypeWriter tw, GenBase type, Field field, CodeGenerationOptions opt)
{
if (field.NeedsProperty)
Expand Down Expand Up @@ -313,7 +311,7 @@ public static void AddSupportedOSPlatform (List<AttributeWriter> attributes, And
{
// There's no sense in writing say 'android15' because we do not support older APIs,
// so those APIs will be available in all of our versions.
if (since > MINIMUM_API_LEVEL && opt.CodeGenerationTarget == Xamarin.Android.Binder.CodeGenerationTarget.XAJavaInterop1)
if (since > opt.MinimumApiLevel && opt.CodeGenerationTarget == Xamarin.Android.Binder.CodeGenerationTarget.XAJavaInterop1)
attributes.Add (new SupportedOSPlatformAttr (since));
}

Expand Down Expand Up @@ -344,7 +342,7 @@ static bool AddObsoletedOSPlatformAttribute (List<AttributeWriter> attributes, s
return false;

// If it was obsoleted in a version earlier than we support (like 15), use a regular [Obsolete] instead
if (!deprecatedSince.HasValue || deprecatedSince.Value <= MINIMUM_API_LEVEL)
if (!deprecatedSince.HasValue || deprecatedSince.Value <= opt.MinimumApiLevel)
return false;

// This is the default Android message, but it isn't useful so remove it
Expand Down
3 changes: 2 additions & 1 deletion src/Mono.Android/Mono.Android.targets
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
<Generator>"$(MicrosoftAndroidSdkOutDir)generator.dll"</Generator>
<_GenFlags>--public --product-version=7</_GenFlags>
<_ApiLevel>--api-level=$(AndroidApiLevel)</_ApiLevel>
<_MinimumApiLevel>--minimum-api-level=$(AndroidMinimumDotNetApiLevel)</_MinimumApiLevel>
<_Out>-o "$(IntermediateOutputPath)mcw"</_Out>
<_Codegen>--codegen-target=XAJavaInterop1</_Codegen>
<_Fixup>--fixup=metadata</_Fixup>
Expand All @@ -144,7 +145,7 @@
<_LangFeatures Condition=" $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '7.0')) ">$(_LangFeatures),obsoleted-platform-attributes</_LangFeatures>
</PropertyGroup>
<Exec
Command="&quot;$(DotNetPreviewTool)&quot; $(Generator) $(_GenFlags) $(_ApiLevel) $(_Out) $(_Codegen) $(_Fixup) $(_Enums1) $(_Enums2) $(_Versions) $(_Annotations) $(_Assembly) $(_TypeMap) $(_LangFeatures) $(_Dirs) $(_Api) $(_WithJavadocXml)"
Command="&quot;$(DotNetPreviewTool)&quot; $(Generator) $(_GenFlags) $(_ApiLevel) $(_MinimumApiLevel) $(_Out) $(_Codegen) $(_Fixup) $(_Enums1) $(_Enums2) $(_Versions) $(_Annotations) $(_Assembly) $(_TypeMap) $(_LangFeatures) $(_Dirs) $(_Api) $(_WithJavadocXml)"
IgnoreStandardErrorWarningFormat="True"
/>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ string[] GetBuildProperties (LocalBuilder builder, AndroidRuntime runtime, bool
var noWarn = new List<string> {
"CA1416",
"CS0414",
"CS0618",
"CS1591",
"XA1005",
"XA4225",
Expand Down
Loading