diff --git a/samples/NativeAOT/JavaInteropRuntime.cs b/samples/NativeAOT/JavaInteropRuntime.cs
index 4e54afeb3ba..8c86e5d264b 100644
--- a/samples/NativeAOT/JavaInteropRuntime.cs
+++ b/samples/NativeAOT/JavaInteropRuntime.cs
@@ -34,10 +34,11 @@ static void JNI_OnUnload (IntPtr vm, IntPtr reserved)
static void init (IntPtr jnienv, IntPtr klass)
{
try {
+ var typeManager = new NativeAotTypeManager ();
var options = new JreRuntimeOptions {
EnvironmentPointer = jnienv,
- TypeManager = new NativeAotTypeManager (),
- ValueManager = new NativeAotValueManager (),
+ TypeManager = typeManager,
+ ValueManager = new NativeAotValueManager (typeManager),
UseMarshalMemberBuilder = false,
JniGlobalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:GREF"),
JniLocalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:LREF"),
diff --git a/samples/NativeAOT/MainActivity.cs b/samples/NativeAOT/MainActivity.cs
index 545983d62fe..aaedc0aef2d 100644
--- a/samples/NativeAOT/MainActivity.cs
+++ b/samples/NativeAOT/MainActivity.cs
@@ -1,15 +1,18 @@
using Android.Runtime;
+using Android.Util;
using System.Reflection;
using System.Runtime.InteropServices;
namespace NativeAOT;
-[Register("my/MainActivity")] // Required for typemap in NativeAotTypeManager
-[Activity(Label = "@string/app_name", MainLauncher = true)]
+// Name required for typemap in NativeAotTypeManager
+[Activity (Label = "@string/app_name", MainLauncher = true, Name = "my.MainActivity")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
+ Log.Debug ("NativeAOT", "MainActivity.OnCreate()");
+
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
diff --git a/samples/NativeAOT/MainApplication.cs b/samples/NativeAOT/MainApplication.cs
new file mode 100644
index 00000000000..e3f2c6f546f
--- /dev/null
+++ b/samples/NativeAOT/MainApplication.cs
@@ -0,0 +1,23 @@
+using Android.Runtime;
+using Android.Util;
+
+///
+/// NOTE: This class is not required, but used for testing Android.App.Application subclasses.
+/// Name required for typemap in NativeAotTypeManager
+///
+[Application (Name = "my.MainApplication")]
+public class MainApplication : Application
+{
+ public MainApplication (IntPtr handle, JniHandleOwnership transfer)
+ : base (handle, transfer)
+ {
+ Log.Debug ("NativeAOT", $"Application..ctor({handle.ToString ("x2")}, {transfer})");
+ }
+
+ public override void OnCreate ()
+ {
+ Log.Debug ("NativeAOT", "Application.OnCreate()");
+
+ base.OnCreate ();
+ }
+}
diff --git a/samples/NativeAOT/NativeAotRuntimeProvider.java b/samples/NativeAOT/NativeAotRuntimeProvider.java
index b87f23f25c7..6de591501d5 100644
--- a/samples/NativeAOT/NativeAotRuntimeProvider.java
+++ b/samples/NativeAOT/NativeAotRuntimeProvider.java
@@ -21,6 +21,8 @@ public boolean onCreate() {
public void attachInfo(android.content.Context context, android.content.pm.ProviderInfo info) {
Log.d(TAG, "NativeAotRuntimeProvider.attachInfo(): calling JavaInteropRuntime.init()…");
JavaInteropRuntime.init();
+ // NOTE: only required for custom applications
+ net.dot.android.ApplicationRegistration.registerApplications();
super.attachInfo (context, info);
}
diff --git a/samples/NativeAOT/NativeAotTypeManager.cs b/samples/NativeAOT/NativeAotTypeManager.cs
index 29499d17847..e8d06af9911 100644
--- a/samples/NativeAOT/NativeAotTypeManager.cs
+++ b/samples/NativeAOT/NativeAotTypeManager.cs
@@ -13,12 +13,14 @@ partial class NativeAotTypeManager : JniRuntime.JniTypeManager {
// TODO: list of types specific to this application
Dictionary typeMappings = new () {
["android/app/Activity"] = typeof (Android.App.Activity),
+ ["android/app/Application"] = typeof (Android.App.Application),
["android/content/Context"] = typeof (Android.Content.Context),
["android/content/ContextWrapper"] = typeof (Android.Content.ContextWrapper),
["android/os/BaseBundle"] = typeof (Android.OS.BaseBundle),
["android/os/Bundle"] = typeof (Android.OS.Bundle),
["android/view/ContextThemeWrapper"] = typeof (Android.Views.ContextThemeWrapper),
["my/MainActivity"] = typeof (MainActivity),
+ ["my/MainApplication"] = typeof (MainApplication),
};
public NativeAotTypeManager ()
diff --git a/samples/NativeAOT/NativeAotValueManager.cs b/samples/NativeAOT/NativeAotValueManager.cs
index 8fb2c55d4e2..e233af7a480 100644
--- a/samples/NativeAOT/NativeAotValueManager.cs
+++ b/samples/NativeAOT/NativeAotValueManager.cs
@@ -1,10 +1,415 @@
+// Originally from: https://github.com/dotnet/java-interop/blob/9b1d8781e8e322849d05efac32119c913b21c192/src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.cs
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
using Android.Runtime;
+using Java.Interop;
namespace NativeAOT;
-// TODO: make a NativeAOT-specific implementation of AndroidValueManager
-// This is enough for "Hello World" to launch
-internal class NativeAotValueManager : AndroidValueManager
+internal class NativeAotValueManager : JniRuntime.JniValueManager
{
+ const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
+ readonly JniRuntime.JniTypeManager TypeManager;
+ Dictionary>? RegisteredInstances = new Dictionary>();
+
+ public NativeAotValueManager(JniRuntime.JniTypeManager typeManager) =>
+ TypeManager = typeManager;
+
+ public override void WaitForGCBridgeProcessing ()
+ {
+ }
+
+ public override void CollectPeers ()
+ {
+ if (RegisteredInstances == null)
+ throw new ObjectDisposedException (nameof (NativeAotValueManager));
+
+ var peers = new List ();
+
+ lock (RegisteredInstances) {
+ foreach (var ps in RegisteredInstances.Values) {
+ foreach (var p in ps) {
+ peers.Add (p);
+ }
+ }
+ RegisteredInstances.Clear ();
+ }
+ List? exceptions = null;
+ foreach (var peer in peers) {
+ try {
+ peer.Dispose ();
+ }
+ catch (Exception e) {
+ exceptions = exceptions ?? new List ();
+ exceptions.Add (e);
+ }
+ }
+ if (exceptions != null)
+ throw new AggregateException ("Exceptions while collecting peers.", exceptions);
+ }
+
+ public override void AddPeer (IJavaPeerable value)
+ {
+ if (RegisteredInstances == null)
+ throw new ObjectDisposedException (nameof (NativeAotValueManager));
+
+ var r = value.PeerReference;
+ if (!r.IsValid)
+ throw new ObjectDisposedException (value.GetType ().FullName);
+ var o = PeekPeer (value.PeerReference);
+ if (o != null)
+ return;
+
+ if (r.Type != JniObjectReferenceType.Global) {
+ value.SetPeerReference (r.NewGlobalRef ());
+ JniObjectReference.Dispose (ref r, JniObjectReferenceOptions.CopyAndDispose);
+ }
+ int key = value.JniIdentityHashCode;
+ lock (RegisteredInstances) {
+ List? peers;
+ if (!RegisteredInstances.TryGetValue (key, out peers)) {
+ peers = new List () {
+ value,
+ };
+ RegisteredInstances.Add (key, peers);
+ return;
+ }
+
+ for (int i = peers.Count - 1; i >= 0; i--) {
+ var p = peers [i];
+ if (!JniEnvironment.Types.IsSameObject (p.PeerReference, value.PeerReference))
+ continue;
+ if (Replaceable (p)) {
+ peers [i] = value;
+ } else {
+ WarnNotReplacing (key, value, p);
+ }
+ return;
+ }
+ peers.Add (value);
+ }
+ }
+
+ static bool Replaceable (IJavaPeerable peer)
+ {
+ if (peer == null)
+ return true;
+ return peer.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable);
+ }
+
+ void WarnNotReplacing (int key, IJavaPeerable ignoreValue, IJavaPeerable keepValue)
+ {
+ Runtime.ObjectReferenceManager.WriteGlobalReferenceLine (
+ "Warning: Not registering PeerReference={0} IdentityHashCode=0x{1} Instance={2} Instance.Type={3} Java.Type={4}; " +
+ "keeping previously registered PeerReference={5} Instance={6} Instance.Type={7} Java.Type={8}.",
+ ignoreValue.PeerReference.ToString (),
+ key.ToString ("x"),
+ RuntimeHelpers.GetHashCode (ignoreValue).ToString ("x"),
+ ignoreValue.GetType ().FullName,
+ JniEnvironment.Types.GetJniTypeNameFromInstance (ignoreValue.PeerReference),
+ keepValue.PeerReference.ToString (),
+ RuntimeHelpers.GetHashCode (keepValue).ToString ("x"),
+ keepValue.GetType ().FullName,
+ JniEnvironment.Types.GetJniTypeNameFromInstance (keepValue.PeerReference));
+ }
+
+ public override IJavaPeerable? PeekPeer (JniObjectReference reference)
+ {
+ if (RegisteredInstances == null)
+ throw new ObjectDisposedException (nameof (NativeAotValueManager));
+
+ if (!reference.IsValid)
+ return null;
+
+ int key = GetJniIdentityHashCode (reference);
+
+ lock (RegisteredInstances) {
+ List? peers;
+ if (!RegisteredInstances.TryGetValue (key, out peers))
+ return null;
+
+ for (int i = peers.Count - 1; i >= 0; i--) {
+ var p = peers [i];
+ if (JniEnvironment.Types.IsSameObject (reference, p.PeerReference))
+ return p;
+ }
+ if (peers.Count == 0)
+ RegisteredInstances.Remove (key);
+ }
+ return null;
+ }
+
+ public override void RemovePeer (IJavaPeerable value)
+ {
+ if (RegisteredInstances == null)
+ throw new ObjectDisposedException (nameof (NativeAotValueManager));
+
+ if (value == null)
+ throw new ArgumentNullException (nameof (value));
+
+ int key = value.JniIdentityHashCode;
+ lock (RegisteredInstances) {
+ List? peers;
+ if (!RegisteredInstances.TryGetValue (key, out peers))
+ return;
+
+ for (int i = peers.Count - 1; i >= 0; i--) {
+ var p = peers [i];
+ if (object.ReferenceEquals (value, p)) {
+ peers.RemoveAt (i);
+ }
+ }
+ if (peers.Count == 0)
+ RegisteredInstances.Remove (key);
+ }
+ }
+
+ public override void FinalizePeer (IJavaPeerable value)
+ {
+ var h = value.PeerReference;
+ var o = Runtime.ObjectReferenceManager;
+ // MUST NOT use SafeHandle.ReferenceType: local refs are tied to a JniEnvironment
+ // and the JniEnvironment's corresponding thread; it's a thread-local value.
+ // Accessing SafeHandle.ReferenceType won't kill anything (so far...), but
+ // instead it always returns JniReferenceType.Invalid.
+ if (!h.IsValid || h.Type == JniObjectReferenceType.Local) {
+ if (o.LogGlobalReferenceMessages) {
+ o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}",
+ h.ToString (),
+ value.JniIdentityHashCode.ToString ("x"),
+ RuntimeHelpers.GetHashCode (value).ToString ("x"),
+ value.GetType ().ToString ());
+ }
+ RemovePeer (value);
+ value.SetPeerReference (new JniObjectReference ());
+ value.Finalized ();
+ return;
+ }
+
+ RemovePeer (value);
+ if (o.LogGlobalReferenceMessages) {
+ o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}",
+ h.ToString (),
+ value.JniIdentityHashCode.ToString ("x"),
+ RuntimeHelpers.GetHashCode (value).ToString ("x"),
+ value.GetType ().ToString ());
+ }
+ value.SetPeerReference (new JniObjectReference ());
+ JniObjectReference.Dispose (ref h);
+ value.Finalized ();
+ }
+
+ public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues)
+ {
+ try {
+ ActivateViaReflection (reference, cinfo, argumentValues);
+ } catch (Exception e) {
+ var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.",
+ reference,
+ GetJniIdentityHashCode (reference).ToString ("x"),
+ JniEnvironment.Types.GetJniTypeNameFromInstance (reference),
+ cinfo.DeclaringType?.FullName);
+ Debug.WriteLine (m);
+
+ throw new NotSupportedException (m, e);
+ }
+ }
+
+ void ActivateViaReflection (JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues)
+ {
+ var declType = cinfo.DeclaringType ?? throw new NotSupportedException ("Do not know the type to create!");
+
+#pragma warning disable IL2072
+ var self = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declType);
+#pragma warning restore IL2072
+ self.SetPeerReference (reference);
+
+ cinfo.Invoke (self, argumentValues);
+ }
+
+ public override List GetSurfacedPeers ()
+ {
+ if (RegisteredInstances == null)
+ throw new ObjectDisposedException (nameof (NativeAotValueManager));
+
+ lock (RegisteredInstances) {
+ var peers = new List (RegisteredInstances.Count);
+ foreach (var e in RegisteredInstances) {
+ foreach (var p in e.Value) {
+ peers.Add (new JniSurfacedPeerInfo (e.Key, new WeakReference (p)));
+ }
+ }
+ return peers;
+ }
+ }
+
+ public override IJavaPeerable? CreatePeer (
+ ref JniObjectReference reference,
+ JniObjectReferenceOptions transfer,
+ [DynamicallyAccessedMembers (Constructors)]
+ Type? targetType)
+ {
+ if (!reference.IsValid) {
+ return null;
+ }
+
+ targetType = targetType ?? typeof (global::Java.Interop.JavaObject);
+ targetType = GetPeerType (targetType);
+
+ if (!typeof (IJavaPeerable).IsAssignableFrom (targetType))
+ throw new ArgumentException ($"targetType `{targetType.AssemblyQualifiedName}` must implement IJavaPeerable!", nameof (targetType));
+
+ var targetSig = Runtime.TypeManager.GetTypeSignature (targetType);
+ if (!targetSig.IsValid || targetSig.SimpleReference == null) {
+ throw new ArgumentException ($"Could not determine Java type corresponding to `{targetType.AssemblyQualifiedName}`.", nameof (targetType));
+ }
+
+ var refClass = JniEnvironment.Types.GetObjectClass (reference);
+ JniObjectReference targetClass;
+ try {
+ targetClass = JniEnvironment.Types.FindClass (targetSig.SimpleReference);
+ } catch (Exception e) {
+ JniObjectReference.Dispose (ref refClass);
+ throw new ArgumentException ($"Could not find Java class `{targetSig.SimpleReference}`.",
+ nameof (targetType),
+ e);
+ }
+
+ if (!JniEnvironment.Types.IsAssignableFrom (refClass, targetClass)) {
+ JniObjectReference.Dispose (ref refClass);
+ JniObjectReference.Dispose (ref targetClass);
+ return null;
+ }
+
+ JniObjectReference.Dispose (ref targetClass);
+
+ var proxy = CreatePeerProxy (ref refClass, targetType, ref reference, transfer);
+
+ if (proxy == null) {
+ throw new NotSupportedException (string.Format ("Could not find an appropriate constructable wrapper type for Java type '{0}', targetType='{1}'.",
+ JniEnvironment.Types.GetJniTypeNameFromInstance (reference), targetType));
+ }
+
+ proxy.SetJniManagedPeerState (proxy.JniManagedPeerState | JniManagedPeerStates.Replaceable);
+ return proxy;
+ }
+
+ [return: DynamicallyAccessedMembers (Constructors)]
+ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type)
+ {
+ if (type == typeof (object))
+ return typeof (global::Java.Interop.JavaObject);
+ if (type == typeof (IJavaPeerable))
+ return typeof (global::Java.Interop.JavaObject);
+ if (type == typeof (Exception))
+ return typeof (global::Java.Interop.JavaException);
+ return type;
+ }
+
+ IJavaPeerable? CreatePeerProxy (
+ ref JniObjectReference klass,
+ [DynamicallyAccessedMembers (Constructors)]
+ Type fallbackType,
+ ref JniObjectReference reference,
+ JniObjectReferenceOptions options)
+ {
+ var jniTypeName = JniEnvironment.Types.GetJniTypeNameFromClass (klass);
+
+ Type? type = null;
+ while (jniTypeName != null) {
+ JniTypeSignature sig;
+ if (!JniTypeSignature.TryParse (jniTypeName, out sig))
+ return null;
+
+ type = Runtime.TypeManager.GetType (sig);
+
+ if (type != null) {
+ var peer = TryCreatePeerProxy (type, ref reference, options);
+ if (peer != null) {
+ return peer;
+ }
+ }
+
+ var super = JniEnvironment.Types.GetSuperclass (klass);
+ jniTypeName = super.IsValid
+ ? JniEnvironment.Types.GetJniTypeNameFromClass (super)
+ : null;
+
+ JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose);
+ klass = super;
+ }
+ JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose);
+
+ return TryCreatePeerProxy (fallbackType, ref reference, options);
+ }
+
+ [return: DynamicallyAccessedMembers (Constructors)]
+ static Type? GetInvokerType (Type type)
+ {
+ // https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L176-L186
+ const string makeGenericTypeMessage = "Generic 'Invoker' types are preserved by the MarkJavaObjects trimmer step.";
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = makeGenericTypeMessage)]
+ [return: DynamicallyAccessedMembers (Constructors)]
+ static Type MakeGenericType (
+ [DynamicallyAccessedMembers (Constructors)]
+ Type type,
+ Type [] arguments) =>
+ // FIXME: https://github.com/dotnet/java-interop/issues/1192
+ #pragma warning disable IL3050
+ type.MakeGenericType (arguments);
+ #pragma warning restore IL3050
+
+ var signature = type.GetCustomAttribute ();
+ if (signature == null || signature.InvokerType == null) {
+ return null;
+ }
+
+ Type[] arguments = type.GetGenericArguments ();
+ if (arguments.Length == 0)
+ return signature.InvokerType;
+
+ return MakeGenericType (signature.InvokerType, arguments);
+ }
+
+ const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+
+
+ static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) };
+ static readonly Type[] JIConstructorSignature = new Type [] { typeof (JniObjectReference).MakeByRefType (), typeof (JniObjectReferenceOptions) };
+
+ protected virtual IJavaPeerable? TryCreatePeerProxy (Type type, ref JniObjectReference reference, JniObjectReferenceOptions options)
+ {
+ var c = type.GetConstructor (ActivationConstructorBindingFlags, null, XAConstructorSignature, null);
+ if (c != null) {
+ var args = new object[] {
+ reference.Handle,
+ JniHandleOwnership.DoNotTransfer,
+ };
+ var p = (IJavaPeerable) c.Invoke (args);
+ JniObjectReference.Dispose (ref reference, options);
+ return p;
+ }
+ c = type.GetConstructor (ActivationConstructorBindingFlags, null, JIConstructorSignature, null);
+ if (c != null) {
+ var args = new object[] {
+ reference,
+ options,
+ };
+ var p = (IJavaPeerable) c.Invoke (args);
+ reference = (JniObjectReference) args [0];
+ return p;
+ }
+ return null;
+ }
}
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
index 685e42403f5..64dd729f9ed 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
@@ -12,6 +12,7 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
<_AndroidRuntimePackRuntime>NativeAOT
+ <_AndroidCodeGenerationTarget Condition=" '$(_AndroidCodeGenerationTarget)' == '' ">JavaInterop1
true
diff --git a/src/Xamarin.Android.Build.Tasks/Resources/ApplicationRegistration.java b/src/Xamarin.Android.Build.Tasks/Resources/ApplicationRegistration.java
index 5f86173d6cd..f14f681c094 100644
--- a/src/Xamarin.Android.Build.Tasks/Resources/ApplicationRegistration.java
+++ b/src/Xamarin.Android.Build.Tasks/Resources/ApplicationRegistration.java
@@ -1,4 +1,4 @@
-package mono.android.app;
+package net.dot.android;
public class ApplicationRegistration {
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
index 766ec7c1465..2fa90dca06e 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
@@ -96,7 +96,10 @@ public class GenerateJavaStubs : AndroidTask
[Required]
public string AndroidRuntime { get; set; } = "";
+ public string CodeGenerationTarget { get; set; } = "";
+
AndroidRuntime androidRuntime;
+ JavaPeerStyle codeGenerationTarget;
internal const string AndroidSkipJavaStubGeneration = "AndroidSkipJavaStubGeneration";
@@ -104,6 +107,7 @@ public override bool RunTask ()
{
try {
androidRuntime = MonoAndroidHelper.ParseAndroidRuntime (AndroidRuntime);
+ codeGenerationTarget = MonoAndroidHelper.ParseCodeGenerationTarget (CodeGenerationTarget);
bool useMarshalMethods = !Debug && EnableMarshalMethods;
Run (useMarshalMethods);
} catch (XamarinAndroidException e) {
@@ -302,22 +306,21 @@ void GenerateAdditionalProviderSources (NativeCodeGenState codeGenState, IList MergeManifest (NativeCodeGenState codeGenState, Dictionary allJavaTypes, List javaTypesForJCW) = ScanForJavaTypes (resolver, tdCache, assemblies, userAssemblies, useMarshalMethods);
var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache, useMarshalMethods);
var jcwGenerator = new JCWGenerator (Log, jcwContext) {
- CodeGenerationTarget = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM ? JavaPeerStyle.XAJavaInterop1 : JavaPeerStyle.JavaInterop1
+ CodeGenerationTarget = codeGenerationTarget,
};
bool success;
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
index 48c1ed3685b..441bd42e5ac 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
@@ -1093,12 +1093,12 @@ public void RemoveOldMonoPackageManager ()
};
var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
var oldMonoPackageManager = Path.Combine (intermediate, "android", "src", "mono", "MonoPackageManager.java");
- var notifyTimeZoneChanges = Path.Combine (intermediate, "android", "src", "mono", "android", "app", "NotifyTimeZoneChanges.java");
+ var notifyTimeZoneChanges = Path.Combine (intermediate, "android", "src", "net", "dot", "android", "NotifyTimeZoneChanges.java");
Directory.CreateDirectory (Path.GetDirectoryName (notifyTimeZoneChanges));
File.WriteAllText (oldMonoPackageManager, @"package mono;
public class MonoPackageManager { }
class MonoPackageManager_Resources { }");
- File.WriteAllText (notifyTimeZoneChanges, @"package mono.android.app;
+ File.WriteAllText (notifyTimeZoneChanges, @"package net.dot.android;
public class ApplicationRegistration { }");
var oldMonoPackageManagerClass = Path.Combine (intermediate, "android", "bin", "classes" , "mono", "MonoPackageManager.class");
File.WriteAllText (oldMonoPackageManagerClass, "");
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs
index 1367ded5abf..5659fba2d37 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs
@@ -9,6 +9,7 @@
using System.Threading;
using Xamarin.Android.Tools;
using Xamarin.Tools.Zip;
+using Java.Interop.Tools.JavaCallableWrappers;
#if MSBUILD
using Microsoft.Android.Build.Tasks;
@@ -830,5 +831,14 @@ public static AndroidRuntime ParseAndroidRuntime (string androidRuntime)
// Default runtime is MonoVM
return AndroidRuntime.MonoVM;
}
+
+ public static JavaPeerStyle ParseCodeGenerationTarget (string codeGenerationTarget)
+ {
+ if (Enum.TryParse (codeGenerationTarget, ignoreCase: true, out JavaPeerStyle style))
+ return style;
+
+ // Default is XAJavaInterop1
+ return JavaPeerStyle.XAJavaInterop1;
+ }
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
index 2739e628b27..3cf94e2657e 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
@@ -1501,6 +1501,7 @@ because xbuild doesn't support framework reference assemblies.
-
+