From 1e95f40daee4d99b424ddf711074b8385cbdd1ee Mon Sep 17 00:00:00 2001
From: Jonathan Peppers <jonathan.peppers@microsoft.com>
Date: Thu, 25 Jun 2020 16:47:22 -0500
Subject: [PATCH] [Microsoft.Android.Ref] support for older targetSdkVersion

Currently, if you build a .NET 5 project that has
`targetSdkVersion="29"` (older than 30):

    error XA5207: Could not find android.jar for API level . This means the Android SDK platform for API level  is not installed. Either install it in the Android SDK Manager (Tools > Android > Android SDK Manager...), or change the Xamarin.Android project to target an API version that is installed. (C:\Users\jopepper\android-toolchain\sdk\platforms\android-\android.jar missing.)

A lot of `string.Empty` appears in the error messages...

This is because we only have one `AndroidApiInfo.xml`:

    <AndroidApiInfo>
      <Id>30</Id>
      <Level>30</Level>
      <Name>R</Name>
      <Version>v11.0</Version>
      <Stable>True</Stable>
    </AndroidApiInfo>

And so calls like `MonoAndroidHelper.SupportedVersions.GetApiLevelFromId`
won't work for API 29, because API 29 is unknown.

To fix this, we should ship *all* of the `AndroidApiInfo.xml` files in
the `Microsoft.Android.Ref.nupkg`, such as:

* `ref\net5.0\Java.Interop.dll`
* `ref\net5.0\Mono.Android.dll`
* `ref\net5.0\v10.0\AndroidApiInfo.xml`
* `ref\net5.0\v11.0\AndroidApiInfo.xml`

The code here will continue to work, because it searches recursively:

https://github.com/xamarin/xamarin-android-tools/blob/3974fc38c0f25f943b5d3bf0a4e174532a2a60ee/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersions.cs#L45-L46

I added a test verifying app with `targetSdkVersion="29"` work under
.NET 5.
---
 build-tools/create-packs/Microsoft.Android.Ref.proj      | 2 +-
 .../Tests/Xamarin.Android.Build.Tests/XASdkTests.cs      | 9 +++++++++
 .../Tests/Xamarin.ProjectTools/Android/XASdkProject.cs   | 4 +++-
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/build-tools/create-packs/Microsoft.Android.Ref.proj b/build-tools/create-packs/Microsoft.Android.Ref.proj
index 147dd5bd11f..d4d9b3ed0d4 100644
--- a/build-tools/create-packs/Microsoft.Android.Ref.proj
+++ b/build-tools/create-packs/Microsoft.Android.Ref.proj
@@ -36,7 +36,7 @@ by projects that use the Microsoft.Android framework in .NET 5.
       <_PackageFiles Include="@(_AndroidAppPackAssemblies)" PackagePath="$(_AndroidRefPackAssemblyPath)" TargetPath="$(_AndroidRefPackAssemblyPath)" />
       <_PackageFiles Include="$(XAInstallPrefix)xbuild-frameworks\Microsoft.Android\netcoreapp3.1\mono.android.jar" PackagePath="$(_AndroidRefPackAssemblyPath)" />
       <_PackageFiles Include="$(XAInstallPrefix)xbuild-frameworks\Microsoft.Android\netcoreapp3.1\mono.android.dex" PackagePath="$(_AndroidRefPackAssemblyPath)" />
-      <_PackageFiles Include="$(XAInstallPrefix)xbuild-frameworks\Microsoft.Android\netcoreapp3.1\AndroidApiInfo.xml" PackagePath="$(_AndroidRefPackAssemblyPath)" />
+      <_PackageFiles Include="$(XAInstallPrefix)xbuild-frameworks\MonoAndroid\*\AndroidApiInfo.xml" PackagePath="$(_AndroidRefPackAssemblyPath)\%(RecursiveDir)" />
     </ItemGroup>
   </Target>
 
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs
index be8a0206e13..ec35779d3e6 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs
@@ -186,6 +186,15 @@ public void DotNetPublish ([Values (false, true)] bool isRelease)
 			FileAssert.Exists (aabSigned);
 		}
 
+		[Test]
+		public void TargetSdkVersion29 ()
+		{
+			var proj = new XASdkProject ();
+			proj.AndroidManifest = proj.AndroidManifest.Replace ("<uses-sdk />", "<uses-sdk android:targetSdkVersion=\"29\" />");
+			var dotnet = CreateDotNetBuilder (proj);
+			Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed");
+		}
+
 		[Test]
 		public void BuildWithLiteSdk ()
 		{
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs
index ef390bba567..ad7e97088e3 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs
@@ -43,6 +43,7 @@ static XASdkProject ()
 
 		public string PackageName { get; set; }
 		public string JavaPackageName { get; set; }
+		public string AndroidManifest { get; set; }
 
 		public XASdkProject (string outputType = "Exe")
 		{
@@ -51,13 +52,14 @@ public XASdkProject (string outputType = "Exe")
 
 			PackageName = PackageName ?? string.Format ("{0}.{0}", ProjectName);
 			JavaPackageName = JavaPackageName ?? PackageName.ToLowerInvariant ();
+			AndroidManifest = default_android_manifest;
 			GlobalPackagesFolder = Path.Combine (XABuildPaths.TopDirectory, "packages");
 			SetProperty (KnownProperties.OutputType, outputType);
 
 			// Add relevant Android content to our project without writing it to the .csproj file
 			if (outputType == "Exe") {
 				Sources.Add (new BuildItem.Source ("Properties\\AndroidManifest.xml") {
-					TextContent = () => default_android_manifest.Replace ("${PROJECT_NAME}", ProjectName).Replace ("${PACKAGENAME}", string.Format ("{0}.{0}", ProjectName))
+					TextContent = () => AndroidManifest.Replace ("${PROJECT_NAME}", ProjectName).Replace ("${PACKAGENAME}", string.Format ("{0}.{0}", ProjectName))
 				});
 			}
 			Sources.Add (new BuildItem.Source ($"MainActivity{Language.DefaultExtension}") { TextContent = () => ProcessSourceTemplate (MainActivity ?? DefaultMainActivity) });
