예제 #1
0
        internal static ExportAttribute ToExportAttribute(CustomAttribute attr, IMemberDefinition declaringMember)
        {
            var name = attr.ConstructorArguments.Count > 0 ? (string)attr.ConstructorArguments [0].Value : declaringMember.Name;

            if (attr.Properties.Count == 0)
            {
                return(new ExportAttribute(name));
            }
            var typeArgs  = (CustomAttributeArgument [])attr.Properties.FirstOrDefault(p => p.Name == "Throws").Argument.Value;
            var thrown    = typeArgs != null && typeArgs.Any() ? (from caa in typeArgs select JavaNativeTypeManager.Parse(GetJniTypeName((TypeReference)caa.Value)).Type).ToArray() : null;
            var superArgs = (string)attr.Properties.FirstOrDefault(p => p.Name == "SuperArgumentsString").Argument.Value;

            return(new ExportAttribute(name)
            {
                ThrownNames = thrown, SuperArgumentsString = superArgs
            });
        }
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;
            var temp = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

            Directory.CreateDirectory(temp);

            var selectedWhitelistAssemblies = new List <string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a))
                {
                    selectedWhitelistAssemblies.Add(Path.GetFullPath(assembly.ItemSpec));
                }
            }

            // However we only want to look for JLO types in user code
            var assemblies  = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)
                              .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a)));

            assemblies = assemblies.Concat(fxAdditions).ToList();

            // Step 1 - Find all the JLO types
            var scanner = new JavaTypeScanner(this.CreateTaskLogger())
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };
            var all_java_types = scanner.GetJavaTypes(assemblies, res);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types.Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t));

            // Step 2 - Generate Java stub code
            var keep_going = Generator.CreateJavaSources(
                Log,
                java_types,
                temp,
                ApplicationJavaClass,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            var temp_map_file = Path.Combine(temp, "acw-map.temp");

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> ();
            var java    = new Dictionary <string, TypeDefinition> ();
            var acw_map = new StreamWriter(temp_map_file);

            foreach (var type in java_types)
            {
                string managedKey = type.FullName.Replace('/', '.');
                string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                acw_map.WriteLine("{0};{1}", type.GetPartialAssemblyQualifiedName(), javaKey);

                TypeDefinition conflict;
                if (managed.TryGetValue(managedKey, out conflict))
                {
                    Log.LogWarning(
                        "Duplicate managed type found! Mappings between managed types and Java types must be unique. " +
                        "First Type: '{0}'; Second Type: '{1}'.",
                        conflict.GetAssemblyQualifiedName(),
                        type.GetAssemblyQualifiedName());
                    Log.LogWarning(
                        "References to the type '{0}' will refer to '{1}'.",
                        managedKey, conflict.GetAssemblyQualifiedName());
                    continue;
                }
                if (java.TryGetValue(javaKey, out conflict))
                {
                    Log.LogError(
                        "Duplicate Java type found! Mappings between managed types and Java types must be unique. " +
                        "First Type: '{0}'; Second Type: '{1}'",
                        conflict.GetAssemblyQualifiedName(),
                        type.GetAssemblyQualifiedName());
                    keep_going = false;
                    continue;
                }
                managed.Add(managedKey, type);
                java.Add(javaKey, type);
                acw_map.WriteLine("{0};{1}", managedKey, javaKey);
                acw_map.WriteLine("{0};{1}", JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'), javaKey);
            }

            acw_map.Close();

            //The previous steps found an error, so we must abort and not generate any further output
            //We must do so subsequent unchanged builds fail too.
            if (!keep_going)
            {
                File.Delete(temp_map_file);
                return;
            }

            MonoAndroidHelper.CopyIfChanged(temp_map_file, AcwMapFile);

            try { File.Delete(temp_map_file); } catch (Exception) { }

            // Only overwrite files if the contents actually changed
            foreach (var file in Directory.GetFiles(temp, "*", SearchOption.AllDirectories))
            {
                var dest = Path.GetFullPath(Path.Combine(OutputDirectory, "src", file.Substring(temp.Length + 1)));

                MonoAndroidHelper.CopyIfChanged(file, dest);
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver      = res;
            manifest.SdkDir        = AndroidSdkDir;
            manifest.SdkVersion    = AndroidSdkPlatform;
            manifest.Debug         = Debug;
            manifest.NeedsInternet = NeedsInternet;

            var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            var temp_manifest = Path.Combine(temp, "AndroidManifest.xml");
            var real_manifest = Path.GetFullPath(MergedAndroidManifestOutput);

            manifest.Save(temp_manifest);

            // Only write the new manifest if it actually changed
            MonoAndroidHelper.CopyIfChanged(temp_manifest, real_manifest);

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = new StreamReader(typeof(JavaCallableWrapperGenerator).Assembly.GetManifestResourceStream(providerTemplateFile)).ReadToEnd();

            foreach (var provider in additionalProviders)
            {
                var temp_provider = Path.Combine(temp, provider + ".java");
                File.WriteAllText(temp_provider, providerTemplate.Replace("MonoRuntimeProvider", provider));
                var real_provider_dir = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono"));
                Directory.CreateDirectory(real_provider_dir);
                var real_provider = Path.Combine(real_provider_dir, provider + ".java");
                MonoAndroidHelper.CopyIfChanged(temp_provider, real_provider);
            }

            // Create additional application java sources.

            Action <string, string, string, Func <string, string> > save = (resource, filename, destDir, applyTemplate) => {
                string temp_file = Path.Combine(temp, filename);
                string template  = applyTemplate(new StreamReader(typeof(GenerateJavaStubs).Assembly.GetManifestResourceStream(resource)).ReadToEnd());
                File.WriteAllText(temp_file, template);
                Directory.CreateDirectory(destDir);
                var real_file = Path.Combine(destDir, filename);
                MonoAndroidHelper.CopyIfChanged(temp_file, real_file);
            };

            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono", "android", "app"));
            string applicationTemplateFile = "ApplicationRegistration.java";

            save(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                 template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";

            save(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);

            // Delete our temp directory
            try { Directory.Delete(temp, true); } catch (Exception) { }
        }
예제 #3
0
        JavaCallableWrapperGenerator(TypeDefinition type, string outerType, Action <string, object[]> log)
        {
            this.type = type;
            this.log  = log;

            if (type.IsEnum || type.IsInterface || type.IsValueType)
            {
                Diagnostic.Error(4200, LookupSource(type), "Can only generate Java wrappers for 'class' types, not type '{0}'.", type.FullName);
            }

            string jniName = JavaNativeTypeManager.ToJniName(type);

            if (jniName == null)
            {
                Diagnostic.Error(4201, LookupSource(type), "Unable to determine Java name for type {0}", type.FullName);
            }
            if (!string.IsNullOrEmpty(outerType))
            {
                string p;
                jniName = jniName.Substring(outerType.Length + 1);
                ExtractJavaNames(outerType, out p, out outerType);
            }
            ExtractJavaNames(jniName, out package, out name);
            if (string.IsNullOrEmpty(package) &&
                (type.IsSubclassOf("Android.App.Activity") ||
                 type.IsSubclassOf("Android.App.Application") ||
                 type.IsSubclassOf("Android.App.Service") ||
                 type.IsSubclassOf("Android.Content.BroadcastReceiver") ||
                 type.IsSubclassOf("Android.Content.ContentProvider")))
            {
                Diagnostic.Error(4203, LookupSource(type), "The Name property must be a fully qualified 'package.TypeName' value, and no package was found for '{0}'.", jniName);
            }

            foreach (MethodDefinition minfo in type.Methods.Where(m => !m.IsConstructor))
            {
                var baseMethods         = GetBaseMethods(minfo);
                var baseRegiteredMethod = baseMethods.FirstOrDefault(m => GetRegisterAttributes(m).Any());
                if (baseRegiteredMethod != null)
                {
                    AddMethod(baseRegiteredMethod, minfo);
                }
                else if (GetExportFieldAttributes(minfo).Any())
                {
                    AddMethod(null, minfo);
                    HasExport = true;
                }
                else if (GetExportAttributes(minfo).Any())
                {
                    AddMethod(null, minfo);
                    HasExport = true;
                }
            }

            foreach (MethodDefinition imethod in type.Interfaces.Select(ifaceInfo => ifaceInfo.InterfaceType)
                     .Select(r => {
                var d = r.Resolve();
                if (d == null)
                {
                    Diagnostic.Error(4204,
                                     LookupSource(type),
                                     "Unable to resolve interface type '{0}'. Are you missing an assembly reference?",
                                     r.FullName);
                }
                return(d);
            })
                     .Where(d => GetRegisterAttributes(d).Any())
                     .SelectMany(d => d.Methods))
            {
                AddMethod(imethod, imethod);
            }

            var ctorTypes = new List <TypeDefinition> ()
            {
                type,
            };

            foreach (var bt in type.GetBaseTypes())
            {
                ctorTypes.Add(bt);
                RegisterAttribute rattr = GetRegisterAttributes(bt).FirstOrDefault();
                if (rattr != null && rattr.DoNotGenerateAcw)
                {
                    break;
                }
            }
            ctorTypes.Reverse();

            var curCtors = new List <MethodDefinition> ();

            foreach (MethodDefinition minfo in type.Methods.Where(m => m.IsConstructor))
            {
                if (GetExportAttributes(minfo).Any())
                {
                    if (minfo.IsStatic)
                    {
                        // Diagnostic.Warning (log, "ExportAttribute does not work on static constructor");
                    }
                    else
                    {
                        AddConstructor(minfo, ctorTypes [0], outerType, null, curCtors, false, true);
                        HasExport = true;
                    }
                }
            }

            AddConstructors(ctorTypes [0], outerType, null, curCtors, true);

            for (int i = 1; i < ctorTypes.Count; ++i)
            {
                var baseCtors = curCtors;
                curCtors = new List <MethodDefinition> ();
                AddConstructors(ctorTypes [i], outerType, baseCtors, curCtors, false);
            }
        }
예제 #4
0
        public override void RegisterNativeMembers(JniType nativeClass, Type type, string methods)
        {
            if (FastRegisterNativeMembers(nativeClass, type, methods))
            {
                return;
            }

            if (string.IsNullOrEmpty(methods))
            {
                base.RegisterNativeMembers(nativeClass, type, methods);
                return;
            }

            string[] members = methods.Split('\n');
            if (members.Length < 2)
            {
                base.RegisterNativeMembers(nativeClass, type, methods);
                return;
            }

            JniNativeMethodRegistration[] natives = new JniNativeMethodRegistration [members.Length - 1];
            for (int i = 0; i < members.Length; ++i)
            {
                string method = members [i];
                if (string.IsNullOrEmpty(method))
                {
                    continue;
                }
                string[] toks = members [i].Split(new[] { ':' }, 4);
                Delegate callback;
                if (toks [2] == "__export__")
                {
                    var mname = toks [0].Substring(2);
                    var minfo = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).Where(m => m.Name == mname && JavaNativeTypeManager.GetJniSignature(m) == toks [1]).FirstOrDefault();
                    if (minfo == null)
                    {
                        throw new InvalidOperationException(String.Format("Specified managed method '{0}' was not found. Signature: {1}", mname, toks [1]));
                    }
                    callback = CreateDynamicCallback(minfo);
                }
                else
                {
                    GetCallbackHandler connector = (GetCallbackHandler)Delegate.CreateDelegate(typeof(GetCallbackHandler),
                                                                                               toks.Length == 4 ? Type.GetType(toks [3], true) : type, toks [2]);
                    callback = connector();
                }
                natives [i] = new JniNativeMethodRegistration(toks [0], toks [1], callback);
            }

            JniEnvironment.Types.RegisterNatives(nativeClass.PeerReference, natives, natives.Length);
        }
예제 #5
0
        public override void RegisterNativeMembers(JniType nativeClass, Type type, string?methods)
        {
            if (FastRegisterNativeMembers(nativeClass, type, methods))
            {
                return;
            }

            if (string.IsNullOrEmpty(methods))
            {
                if (jniAddNativeMethodRegistrationAttributePresent)
                {
                    base.RegisterNativeMembers(nativeClass, type, methods);
                }
                return;
            }

            string[] members = methods !.Split('\n');
            if (members.Length < 2)
            {
                if (jniAddNativeMethodRegistrationAttributePresent)
                {
                    base.RegisterNativeMembers(nativeClass, type, methods);
                }
                return;
            }

            JniNativeMethodRegistration[] natives = new JniNativeMethodRegistration [members.Length - 1];
            for (int i = 0; i < members.Length; ++i)
            {
                string method = members [i];
                if (string.IsNullOrEmpty(method))
                {
                    continue;
                }
                string[] toks = members [i].Split(new[] { ':' }, 4);
                Delegate callback;
                if (toks [2] == "__export__")
                {
                    var        mname = toks [0].Substring(2);
                    MethodInfo?minfo = null;
                    foreach (var mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
                    {
                        if (mi.Name == mname && JavaNativeTypeManager.GetJniSignature(mi) == toks [1])
                        {
                            minfo = mi;
                            break;
                        }
                    }

                    if (minfo == null)
                    {
                        throw new InvalidOperationException(String.Format("Specified managed method '{0}' was not found. Signature: {1}", mname, toks [1]));
                    }
                    callback = CreateDynamicCallback(minfo);
                }
                else
                {
                    Type callbackDeclaringType = type;
                    if (toks.Length == 4)
                    {
                        callbackDeclaringType = Type.GetType(toks [3], throwOnError: true) !;
                    }
                    while (callbackDeclaringType.ContainsGenericParameters)
                    {
                        callbackDeclaringType = callbackDeclaringType.BaseType !;
                    }
                    GetCallbackHandler connector = (GetCallbackHandler)Delegate.CreateDelegate(typeof(GetCallbackHandler),
                                                                                               callbackDeclaringType, toks [2]);
                    callback = connector();
                }
                natives [i] = new JniNativeMethodRegistration(toks [0], toks [1], callback);
            }

            JniEnvironment.Types.RegisterNatives(nativeClass.PeerReference, natives, natives.Length);
        }
예제 #6
0
 static bool CannotRegisterInStaticConstructor(TypeDefinition type)
 {
     return(JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type));
 }
예제 #7
0
 public void Lowercase()
 {
     JavaNativeTypeManager.PackageNamingPolicy = PackageNamingPolicy.Lowercase;
     Assert.AreEqual("system", JavaNativeTypeManager.GetPackageName(typeof(string)));
 }
 public static string ToString(TypeDefinition typeDef)
 {
     return(JavaNativeTypeManager.ToJniName(typeDef).Replace('/', '.'));
 }
예제 #9
0
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            var selectedWhitelistAssemblies = new List <string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                var assemblyFullPath = Path.GetFullPath(assembly.ItemSpec);
                res.Load(assemblyFullPath);
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a))
                {
                    selectedWhitelistAssemblies.Add(assemblyFullPath);
                }
            }

            // However we only want to look for JLO types in user code
            var assemblies  = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)
                              .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a)));

            assemblies = assemblies.Concat(fxAdditions).ToList();

            // Step 1 - Find all the JLO types
            var scanner = new JavaTypeScanner(this.CreateTaskLogger())
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };
            var all_java_types = scanner.GetJavaTypes(assemblies, res);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types
                             .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t))
                             .ToArray();

            // Step 2 - Generate Java stub code
            var success = Generator.CreateJavaSources(
                Log,
                java_types,
                Path.Combine(OutputDirectory, "src"),
                ApplicationJavaClass,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);

            // Allocate a MemoryStream with a reasonable guess at its capacity
            using (var stream = new MemoryStream(java_types.Length * 32))
                using (var acw_map = new StreamWriter(stream)) {
                    foreach (var type in java_types)
                    {
                        string managedKey = type.FullName.Replace('/', '.');
                        string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                        acw_map.Write(type.GetPartialAssemblyQualifiedName());
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        TypeDefinition conflict;
                        if (managed.TryGetValue(managedKey, out conflict))
                        {
                            Log.LogWarning(
                                "Duplicate managed type found! Mappings between managed types and Java types must be unique. " +
                                "First Type: '{0}'; Second Type: '{1}'.",
                                conflict.GetAssemblyQualifiedName(),
                                type.GetAssemblyQualifiedName());
                            Log.LogWarning(
                                "References to the type '{0}' will refer to '{1}'.",
                                managedKey, conflict.GetAssemblyQualifiedName());
                            continue;
                        }
                        if (java.TryGetValue(javaKey, out conflict))
                        {
                            Log.LogError(
                                "Duplicate Java type found! Mappings between managed types and Java types must be unique. " +
                                "First Type: '{0}'; Second Type: '{1}'",
                                conflict.GetAssemblyQualifiedName(),
                                type.GetAssemblyQualifiedName());
                            success = false;
                            continue;
                        }

                        managed.Add(managedKey, type);
                        java.Add(javaKey, type);

                        acw_map.Write(managedKey);
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'));
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();
                    }

                    acw_map.Flush();
                    MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile);
                }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            using (var stream = new MemoryStream()) {
                manifest.Save(stream);

                // Only write the new manifest if it actually changed
                MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput);
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource <JavaCallableWrapperGenerator> (providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";

            SaveResource(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);
        }
예제 #10
0
        public IList <string> Merge(List <TypeDefinition> subclasses, List <string> selectedWhitelistAssemblies, string applicationClass, bool embed, string bundledWearApplicationName, IEnumerable <string> mergedManifestDocuments)
        {
            string applicationName = ApplicationName;

            var manifest = doc.Root;

            if (manifest == null || manifest.Name != "manifest")
            {
                throw new Exception("Root element must be 'manifest'");
            }

            var manifest_package = (string)manifest.Attribute("package");

            if (!string.IsNullOrWhiteSpace(manifest_package))
            {
                PackageName = manifest_package;
            }

            manifest.SetAttributeValue(XNamespace.Xmlns + "android", "http://schemas.android.com/apk/res/android");
            if (manifest.Attribute(androidNs + "versionCode") == null)
            {
                manifest.SetAttributeValue(androidNs + "versionCode", "1");
            }
            if (manifest.Attribute(androidNs + "versionName") == null)
            {
                manifest.SetAttributeValue(androidNs + "versionName", "1.0");
            }

            app = CreateApplicationElement(manifest, applicationClass, subclasses, selectedWhitelistAssemblies);

            if (app.Attribute(androidNs + "label") == null && applicationName != null)
            {
                app.SetAttributeValue(androidNs + "label", applicationName);
            }

            var existingTypes = new HashSet <string> (
                app.Descendants().Select(a => (string)a.Attribute(attName)).Where(v => v != null));

            if (!string.IsNullOrEmpty(bundledWearApplicationName))
            {
                if (!app.Elements("meta-data").Any(e => e.Attributes(androidNs + "name").Any(a => a.Value == bundledWearApplicationName)))
                {
                    app.Add(new XElement("meta-data", new XAttribute(androidNs + "name", "com.google.android.wearable.beta.app"), new XAttribute(androidNs + "resource", "@xml/wearable_app_desc")));
                }
            }

            // If no <uses-sdk> is specified, add it with both minSdkVersion and
            // targetSdkVersion set to TargetFrameworkVersion
            if (!manifest.Elements("uses-sdk").Any())
            {
                manifest.AddFirst(
                    new XElement("uses-sdk",
                                 new XAttribute(androidNs + "minSdkVersion", SdkVersionName),
                                 new XAttribute(androidNs + "targetSdkVersion", SdkVersionName)));
            }

            // If no minSdkVersion is specified, set it to TargetFrameworkVersion
            var uses = manifest.Element("uses-sdk");

            if (uses.Attribute(androidNs + "minSdkVersion") == null)
            {
                int minSdkVersion;
                if (!int.TryParse(SdkVersionName, out minSdkVersion))
                {
                    minSdkVersion = 11;
                }
                minSdkVersion = Math.Min(minSdkVersion, 11);
                uses.SetAttributeValue(androidNs + "minSdkVersion", minSdkVersion.ToString());
            }

            string targetSdkVersion;
            var    tsv = uses.Attribute(androidNs + "targetSdkVersion");

            if (tsv != null)
            {
                targetSdkVersion = tsv.Value;
            }
            else
            {
                targetSdkVersion = SdkVersionName;
                uses.AddBeforeSelf(new XComment("suppress UsesMinSdkAttributes"));
            }

            int?tryTargetSdkVersion = MonoAndroidHelper.SupportedVersions.GetApiLevelFromId(targetSdkVersion);

            if (!tryTargetSdkVersion.HasValue)
            {
                throw new InvalidOperationException(string.Format("The targetSdkVersion ({0}) is not a valid API level", targetSdkVersion));
            }
            int targetSdkVersionValue = tryTargetSdkVersion.Value;

            foreach (var t in subclasses)
            {
                if (t.IsAbstract)
                {
                    continue;
                }

                if (PackageName == null)
                {
                    PackageName = t.Namespace;
                }

                var name       = JavaNativeTypeManager.ToJniName(t).Replace('/', '.');
                var compatName = JavaNativeTypeManager.ToCompatJniName(t).Replace('/', '.');
                if (((string)app.Attribute(attName)) == compatName)
                {
                    app.SetAttributeValue(attName, name);
                }

                Func <TypeDefinition, string, int, XElement> generator = GetGenerator(t);
                if (generator == null)
                {
                    continue;
                }

                try {
                    // activity not present: create a launcher for it IFF it has attribute
                    if (!existingTypes.Contains(name) && !existingTypes.Contains(compatName))
                    {
                        XElement fromCode = generator(t, name, targetSdkVersionValue);
                        if (fromCode == null)
                        {
                            continue;
                        }

                        if (!t.Methods.Where(m => m.IsConstructor).Cast <MethodDefinition> ().Any(c => !c.HasParameters && c.IsPublic))
                        {
                            throw new InvalidOperationException(string.Format("The type '{0}' needs to have a public default constructor.",
                                                                              t.FullName));
                        }
                        app.Add(fromCode);
                    }
                    foreach (var d in app.Descendants().Where(a => ((string)a.Attribute(attName)) == compatName))
                    {
                        d.SetAttributeValue(attName, name);
                    }
                } catch (InvalidActivityNameException ex) {
                    log.LogErrorFromException(ex);
                }
            }

            var icon = app.Attribute(androidNs + "icon");

            if (icon == null)
            {
                var activity = app.Element("activity");
                if (activity != null)
                {
                    var activityIcon = activity.Attribute(androidNs + "icon");
                    if (activityIcon != null)
                    {
                        app.Add(new XAttribute(androidNs + "icon", activityIcon.Value));
                    }
                }
            }

            PackageName = AndroidAppManifest.CanonicalizePackageName(PackageName);

            if (!PackageName.Contains('.'))
            {
                throw new InvalidOperationException("/manifest/@package attribute MUST contain a period ('.').");
            }

            manifest.SetAttributeValue("package", PackageName);

            var providerNames = AddMonoRuntimeProviders(app);

            if (Debug)
            {
                app.Add(new XComment("suppress ExportedReceiver"));
                app.Add(new XElement("receiver",
                                     new XAttribute(androidNs + "name", "mono.android.Seppuku"),
                                     new XElement("intent-filter",
                                                  new XElement("action",
                                                               new XAttribute(androidNs + "name", "mono.android.intent.action.SEPPUKU")),
                                                  new XElement("category",
                                                               new XAttribute(androidNs + "name", "mono.android.intent.category.SEPPUKU." + PackageName)))));
                if (app.Attribute(androidNs + "debuggable") == null)
                {
                    app.Add(new XAttribute(androidNs + "debuggable", "true"));
                }
            }
            if (Debug || NeedsInternet)
            {
                AddInternetPermissionForDebugger();
            }

            if (!embed)
            {
                AddFastDeployPermissions();
            }

            AddAddOns(app, SdkDir, SdkVersionName, Addons);

            // If the manifest has android:installLocation, but we are targeting
            // API 7 or lower, remove it for the user and show a warning
            if (manifest.Attribute(androidNs + "installLocation") != null)
            {
                if (targetSdkVersionValue < 8)
                {
                    manifest.Attribute(androidNs + "installLocation").Remove();
                    Console.Error.WriteLine("monodroid: warning 1 : installLocation cannot be specified for Android versions less than 2.2.  Attribute installLocation ignored.");
                }
            }

            AddInstrumentations(manifest, subclasses, targetSdkVersionValue);
            AddPermissions(app, selectedWhitelistAssemblies);
            AddPermissionGroups(app, selectedWhitelistAssemblies);
            AddPermissionTrees(app, selectedWhitelistAssemblies);
            AddUsesPermissions(app, selectedWhitelistAssemblies);
            AddUsesFeatures(app, selectedWhitelistAssemblies);
            AddSupportsGLTextures(app, selectedWhitelistAssemblies);

            ReorderActivityAliases(app);
            ReorderElements(app);

            if (mergedManifestDocuments != null)
            {
                foreach (var mergedManifest in mergedManifestDocuments)
                {
                    try {
                        MergeLibraryManifest(mergedManifest);
                    } catch (Exception ex) {
                        log.LogWarningFromException(ex);
                    }
                }
            }

            return(providerNames);
        }
예제 #11
0
        public IList <string> Merge(List <TypeDefinition> subclasses, string applicationClass, bool embed, string bundledWearApplicationName)
        {
            string applicationName = ApplicationName;

            var manifest = doc.Root;

            if (manifest == null || manifest.Name != "manifest")
            {
                throw new Exception("Root element must be 'manifest'");
            }

            var manifest_package = (string)manifest.Attribute("package");

            if (!string.IsNullOrWhiteSpace(manifest_package))
            {
                PackageName = manifest_package;
            }

            manifest.SetAttributeValue(XNamespace.Xmlns + "android", "http://schemas.android.com/apk/res/android");
            if (manifest.Attribute(androidNs + "versionCode") == null)
            {
                manifest.SetAttributeValue(androidNs + "versionCode", "1");
            }
            if (manifest.Attribute(androidNs + "versionName") == null)
            {
                manifest.SetAttributeValue(androidNs + "versionName", "1.0");
            }

            app = CreateApplicationElement(manifest, applicationClass, subclasses);

            if (app.Attribute(androidNs + "label") == null && applicationName != null)
            {
                app.SetAttributeValue(androidNs + "label", applicationName);
            }

            var existingTypes = new HashSet <string> (
                app.Descendants().Select(a => (string)a.Attribute(attName)).Where(v => v != null));

            if (!string.IsNullOrEmpty(bundledWearApplicationName))
            {
                if (!app.Elements("meta-data").Any(e => e.Attributes(androidNs + "name").Any(a => a.Value == bundledWearApplicationName)))
                {
                    app.Add(new XElement("meta-data", new XAttribute(androidNs + "name", "com.google.android.wearable.beta.app"), new XAttribute(androidNs + "resource", "@xml/wearable_app_desc")));
                }
            }

            // If no <uses-sdk> is specified, add it with both minSdkVersion and
            // targetSdkVersion set to TargetFrameworkVersion
            if (!manifest.Elements("uses-sdk").Any())
            {
                manifest.AddFirst(
                    new XElement("uses-sdk",
                                 new XAttribute(androidNs + "minSdkVersion", SdkVersionName),
                                 new XAttribute(androidNs + "targetSdkVersion", SdkVersionName)));
            }

            // If no minSdkVersion is specified, set it to TargetFrameworkVersion
            var uses = manifest.Element("uses-sdk");

            if (uses.Attribute(androidNs + "minSdkVersion") == null)
            {
                int minSdkVersion;
                if (!int.TryParse(SdkVersionName, out minSdkVersion))
                {
                    minSdkVersion = XABuildConfig.NDKMinimumApiAvailable;
                }
                minSdkVersion = Math.Min(minSdkVersion, XABuildConfig.NDKMinimumApiAvailable);
                uses.SetAttributeValue(androidNs + "minSdkVersion", minSdkVersion.ToString());
            }

            string targetSdkVersion;
            var    tsv = uses.Attribute(androidNs + "targetSdkVersion");

            if (tsv != null)
            {
                targetSdkVersion = tsv.Value;
            }
            else
            {
                targetSdkVersion = SdkVersionName;
                uses.AddBeforeSelf(new XComment("suppress UsesMinSdkAttributes"));
            }

            int?tryTargetSdkVersion = MonoAndroidHelper.SupportedVersions.GetApiLevelFromId(targetSdkVersion);

            if (!tryTargetSdkVersion.HasValue)
            {
                throw new InvalidOperationException(string.Format("The targetSdkVersion ({0}) is not a valid API level", targetSdkVersion));
            }
            int targetSdkVersionValue = tryTargetSdkVersion.Value;

            foreach (var t in subclasses)
            {
                if (t.IsAbstract)
                {
                    continue;
                }

                if (PackageName == null)
                {
                    PackageName = t.Namespace;
                }

                var name       = JavaNativeTypeManager.ToJniName(t).Replace('/', '.');
                var compatName = JavaNativeTypeManager.ToCompatJniName(t).Replace('/', '.');
                if (((string)app.Attribute(attName)) == compatName)
                {
                    app.SetAttributeValue(attName, name);
                }

                Func <TypeDefinition, string, int, XElement> generator = GetGenerator(t);
                if (generator == null)
                {
                    continue;
                }

                try {
                    // activity not present: create a launcher for it IFF it has attribute
                    if (!existingTypes.Contains(name) && !existingTypes.Contains(compatName))
                    {
                        XElement fromCode = generator(t, name, targetSdkVersionValue);
                        if (fromCode == null)
                        {
                            continue;
                        }

                        IEnumerable <MethodDefinition> constructors = t.Methods.Where(m => m.IsConstructor).Cast <MethodDefinition> ();
                        if (!constructors.Any(c => !c.HasParameters && c.IsPublic))
                        {
                            string        message        = $"The type '{t.FullName}' must provide a public default constructor";
                            SequencePoint sourceLocation = FindSource(constructors);

                            if (sourceLocation != null && sourceLocation.Document?.Url != null)
                            {
                                log.LogError(
                                    subcategory:      String.Empty,
                                    errorCode:        "XA4213",
                                    helpKeyword:      String.Empty,
                                    file:             sourceLocation.Document.Url,
                                    lineNumber:       sourceLocation.StartLine,
                                    columnNumber:     sourceLocation.StartColumn,
                                    endLineNumber:    sourceLocation.EndLine,
                                    endColumnNumber:  sourceLocation.EndColumn,
                                    message:          message);
                            }
                            else
                            {
                                log.LogCodedError("XA4213", message);
                            }
                            continue;
                        }
                        app.Add(fromCode);
                    }
                    foreach (var d in app.Descendants().Where(a => ((string)a.Attribute(attName)) == compatName))
                    {
                        d.SetAttributeValue(attName, name);
                    }
                } catch (InvalidActivityNameException ex) {
                    log.LogErrorFromException(ex);
                }
            }

            var icon = app.Attribute(androidNs + "icon");

            if (icon == null)
            {
                var activity = app.Element("activity");
                if (activity != null)
                {
                    var activityIcon = activity.Attribute(androidNs + "icon");
                    if (activityIcon != null)
                    {
                        app.Add(new XAttribute(androidNs + "icon", activityIcon.Value));
                    }
                }
            }

            PackageName = AndroidAppManifest.CanonicalizePackageName(PackageName);

            if (!PackageName.Contains('.'))
            {
                throw new InvalidOperationException("/manifest/@package attribute MUST contain a period ('.').");
            }

            manifest.SetAttributeValue("package", PackageName);

            if (MultiDex)
            {
                app.Add(CreateMonoRuntimeProvider("mono.android.MultiDexLoader", null, initOrder: --AppInitOrder));
            }

            var providerNames = AddMonoRuntimeProviders(app);

            if (Debug && !embed && InstantRunEnabled)
            {
                if (int.TryParse(SdkVersion, out int apiLevel) && apiLevel >= 19)
                {
                    app.Add(CreateMonoRuntimeProvider("mono.android.ResourcePatcher", null, initOrder: --AppInitOrder));
                }
            }
            if (Debug)
            {
                app.Add(new XComment("suppress ExportedReceiver"));
                app.Add(new XElement("receiver",
                                     new XAttribute(androidNs + "name", "mono.android.Seppuku"),
                                     new XElement("intent-filter",
                                                  new XElement("action",
                                                               new XAttribute(androidNs + "name", "mono.android.intent.action.SEPPUKU")),
                                                  new XElement("category",
                                                               new XAttribute(androidNs + "name", "mono.android.intent.category.SEPPUKU." + PackageName)))));
                if (app.Attribute(androidNs + "debuggable") == null)
                {
                    app.Add(new XAttribute(androidNs + "debuggable", "true"));
                }
            }
            if (Debug || NeedsInternet)
            {
                AddInternetPermissionForDebugger();
            }

            if (!embed)
            {
                AddFastDeployPermissions();
            }

            // If the manifest has android:installLocation, but we are targeting
            // API 7 or lower, remove it for the user and show a warning
            if (manifest.Attribute(androidNs + "installLocation") != null)
            {
                if (targetSdkVersionValue < 8)
                {
                    manifest.Attribute(androidNs + "installLocation").Remove();
                    Console.Error.WriteLine("monodroid: warning 1 : installLocation cannot be specified for Android versions less than 2.2.  Attribute installLocation ignored.");
                }
            }

            AddInstrumentations(manifest, subclasses, targetSdkVersionValue);
            AddPermissions(app);
            AddPermissionGroups(app);
            AddPermissionTrees(app);
            AddUsesPermissions(app);
            AddUsesFeatures(app);
            AddSupportsGLTextures(app);

            ReorderActivityAliases(app);
            ReorderElements(app);

            return(providerNames);

            SequencePoint FindSource(IEnumerable <MethodDefinition> methods)
            {
                if (methods == null)
                {
                    return(null);
                }

                SequencePoint ret = null;

                foreach (MethodDefinition method in methods.Where(m => m != null && m.HasBody && m.DebugInformation != null))
                {
                    foreach (Instruction ins in method.Body.Instructions)
                    {
                        SequencePoint seq = method.DebugInformation.GetSequencePoint(ins);
                        if (seq == null)
                        {
                            continue;
                        }

                        if (ret == null || seq.StartLine < ret.StartLine)
                        {
                            ret = seq;
                        }
                        break;
                    }
                }

                return(ret);
            }
        }
예제 #12
0
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            var selectedWhitelistAssemblies = new List <string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                var assemblyFullPath = Path.GetFullPath(assembly.ItemSpec);
                res.Load(assemblyFullPath);
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a))
                {
                    selectedWhitelistAssemblies.Add(assemblyFullPath);
                }
            }

            // However we only want to look for JLO types in user code
            var assemblies  = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)
                              .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a)));

            assemblies = assemblies.Concat(fxAdditions).ToList();

            // Step 1 - Find all the JLO types
            var scanner = new JavaTypeScanner(this.CreateTaskLogger())
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };
            var all_java_types = scanner.GetJavaTypes(assemblies, res);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types
                             .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t))
                             .ToArray();

            // Step 2 - Generate Java stub code
            var success = Generator.CreateJavaSources(
                Log,
                java_types,
                Path.Combine(OutputDirectory, "src"),
                ApplicationJavaClass,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);

            var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);
            var javaConflicts    = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);

            // Allocate a MemoryStream with a reasonable guess at its capacity
            using (var stream = new MemoryStream(java_types.Length * 32))
                using (var acw_map = new StreamWriter(stream)) {
                    foreach (var type in java_types)
                    {
                        string managedKey = type.FullName.Replace('/', '.');
                        string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                        acw_map.Write(type.GetPartialAssemblyQualifiedName());
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        TypeDefinition conflict;
                        bool           hasConflict = false;
                        if (managed.TryGetValue(managedKey, out conflict))
                        {
                            if (!managedConflicts.TryGetValue(managedKey, out var list))
                            {
                                managedConflicts.Add(managedKey, list = new List <string> {
                                    conflict.GetPartialAssemblyName()
                                });
                            }
                            list.Add(type.GetPartialAssemblyName());
                            hasConflict = true;
                        }
                        if (java.TryGetValue(javaKey, out conflict))
                        {
                            if (!javaConflicts.TryGetValue(javaKey, out var list))
                            {
                                javaConflicts.Add(javaKey, list = new List <string> {
                                    conflict.GetAssemblyQualifiedName()
                                });
                            }
                            list.Add(type.GetAssemblyQualifiedName());
                            success     = false;
                            hasConflict = true;
                        }
                        if (!hasConflict)
                        {
                            managed.Add(managedKey, type);
                            java.Add(javaKey, type);

                            acw_map.Write(managedKey);
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();

                            acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'));
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();
                        }
                    }

                    acw_map.Flush();
                    MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile);
                }

            foreach (var kvp in managedConflicts)
            {
                Log.LogCodedWarning(
                    "XA4214",
                    "The managed type `{0}` exists in multiple assemblies: {1}. " +
                    "Please refactor the managed type names in these assemblies so that they are not identical.",
                    kvp.Key,
                    string.Join(", ", kvp.Value));
                Log.LogCodedWarning("XA4214", "References to the type `{0}` will refer to `{0}, {1}`.", kvp.Key, kvp.Value [0]);
            }

            foreach (var kvp in javaConflicts)
            {
                Log.LogCodedError(
                    "XA4215",
                    "The Java type `{0}` is generated by more than one managed type. " +
                    "Please change the [Register] attribute so that the same Java type is not emitted.",
                    kvp.Key);
                foreach (var typeName in kvp.Value)
                {
                    Log.LogCodedError("XA4215", "  `{0}` generated by: {1}", kvp.Key, typeName);
                }
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            using (var stream = new MemoryStream()) {
                manifest.Save(stream);

                // Only write the new manifest if it actually changed
                MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput);
            }

            // Create the CacheFile if needed
            if (!string.IsNullOrEmpty(CacheFile))
            {
                bool extractNativeLibraries = manifest.ExtractNativeLibraries();
                if (!extractNativeLibraries)
                {
                    //We need to write the value to a file, if _GenerateJavaStubs is skipped on incremental builds
                    var document = new XDocument(
                        new XDeclaration("1.0", "UTF-8", null),
                        new XElement("Properties", new XElement(nameof(ReadJavaStubsCache.EmbeddedDSOsEnabled), "True"))
                        );
                    document.SaveIfChanged(CacheFile);
                }
                else
                {
                    //Delete the file otherwise, since we only need to specify when EmbeddedDSOsEnabled=True
                    File.Delete(CacheFile);
                }
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource <JavaCallableWrapperGenerator> (providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";

            SaveResource(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);
        }
예제 #13
0
        public static void GenerateTypeRegistrations(CodeGenerationOptions opt, GenerationInfo gen_info)
        {
            StreamWriter sw = gen_info.Writer = gen_info.OpenStream(opt.GetFileName("Java.Interop.__TypeRegistrations"));

            Dictionary <string, List <KeyValuePair <string, string> > > mapping = new Dictionary <string, List <KeyValuePair <string, string> > >();

            foreach (KeyValuePair <string, string> reg in gen_info.TypeRegistrations)
            {
                int    ls      = reg.Key.LastIndexOf('/');
                string package = ls >= 0 ? reg.Key.Substring(0, ls) : "";

                if (JavaNativeTypeManager.ToCliType(reg.Key) == reg.Value)
                {
                    continue;
                }
                List <KeyValuePair <string, string> > v;
                if (!mapping.TryGetValue(package, out v))
                {
                    mapping.Add(package, v = new List <KeyValuePair <string, string> >());
                }
                v.Add(new KeyValuePair <string, string>(reg.Key, reg.Value));
            }

            sw.WriteLine("using System;");
            sw.WriteLine("using System.Collections.Generic;");
            sw.WriteLine("using Android.Runtime;");
            sw.WriteLine();
            sw.WriteLine("namespace Java.Interop {");
            sw.WriteLine();
            sw.WriteLine("\tpartial class __TypeRegistrations {");
            sw.WriteLine();
            sw.WriteLine("\t\tpublic static void RegisterPackages ()");
            sw.WriteLine("\t\t{");
            sw.WriteLine("#if MONODROID_TIMING");
            sw.WriteLine("\t\t\tvar start = DateTime.Now;");
            sw.WriteLine("\t\t\tAndroid.Util.Log.Info (\"MonoDroid-Timing\", \"RegisterPackages start: \" + (start - new DateTime (1970, 1, 1)).TotalMilliseconds);");
            sw.WriteLine("#endif // def MONODROID_TIMING");
            sw.WriteLine("\t\t\tJava.Interop.TypeManager.RegisterPackages (");
            sw.WriteLine("\t\t\t\t\tnew string[]{");
            foreach (KeyValuePair <string, List <KeyValuePair <string, string> > > e in mapping)
            {
                sw.WriteLine("\t\t\t\t\t\t\"{0}\",", e.Key);
            }
            sw.WriteLine("\t\t\t\t\t},");
            sw.WriteLine("\t\t\t\t\tnew Converter<string, Type>[]{");
            foreach (KeyValuePair <string, List <KeyValuePair <string, string> > > e in mapping)
            {
                sw.WriteLine("\t\t\t\t\t\tlookup_{0}_package,", e.Key.Replace('/', '_'));
            }
            sw.WriteLine("\t\t\t\t\t});");
            sw.WriteLine("#if MONODROID_TIMING");
            sw.WriteLine("\t\t\tvar end = DateTime.Now;");
            sw.WriteLine("\t\t\tAndroid.Util.Log.Info (\"MonoDroid-Timing\", \"RegisterPackages time: \" + (end - new DateTime (1970, 1, 1)).TotalMilliseconds + \" [elapsed: \" + (end - start).TotalMilliseconds + \" ms]\");");
            sw.WriteLine("#endif // def MONODROID_TIMING");
            sw.WriteLine("\t\t}");
            sw.WriteLine();
            sw.WriteLine("\t\tstatic Type Lookup (string[] mappings, string javaType)");
            sw.WriteLine("\t\t{");
            sw.WriteLine("\t\t\tstring managedType = Java.Interop.TypeManager.LookupTypeMapping (mappings, javaType);");
            sw.WriteLine("\t\t\tif (managedType == null)");
            sw.WriteLine("\t\t\t\treturn null;");
            sw.WriteLine("\t\t\treturn Type.GetType (managedType);");
            sw.WriteLine("\t\t}");
            foreach (KeyValuePair <string, List <KeyValuePair <string, string> > > map in mapping)
            {
                sw.WriteLine();
                string package = map.Key.Replace('/', '_');
                sw.WriteLine("\t\tstatic string[] package_{0}_mappings;", package);
                sw.WriteLine("\t\tstatic Type lookup_{0}_package (string klass)", package);
                sw.WriteLine("\t\t{");
                sw.WriteLine("\t\t\tif (package_{0}_mappings == null) {{", package);
                sw.WriteLine("\t\t\t\tpackage_{0}_mappings = new string[]{{", package);
                map.Value.Sort((a, b) => a.Key.CompareTo(b.Key));
                foreach (KeyValuePair <string, string> t in map.Value)
                {
                    sw.WriteLine("\t\t\t\t\t\"{0}:{1}\",", t.Key, t.Value);
                }
                sw.WriteLine("\t\t\t\t};");
                sw.WriteLine("\t\t\t}");
                sw.WriteLine("");
                sw.WriteLine("\t\t\treturn Lookup (package_{0}_mappings, klass);", package);
                sw.WriteLine("\t\t}");
            }
            sw.WriteLine("\t}");
            sw.WriteLine("}");
            sw.Close();
            gen_info.Writer = null;
        }
예제 #14
0
 public void LowercaseWithAssemblyName()
 {
     JavaNativeTypeManager.PackageNamingPolicy = PackageNamingPolicy.LowercaseWithAssemblyName;
     Assert.AreEqual("assembly_mscorlib.system", JavaNativeTypeManager.GetPackageName(typeof(string)));
 }
예제 #15
0
 static string GetJniTypeName(TypeReference typeRef, ExportParameterKind exportKind)
 {
     return(JavaNativeTypeManager.GetJniTypeName(typeRef, exportKind));
 }
예제 #16
0
        JavaCallableWrapperGenerator(TypeDefinition type, string outerType, Action <string, object[]> log, IMetadataResolver resolver)
        {
            this.type  = type;
            this.log   = log;
            this.cache = resolver ?? new TypeDefinitionCache();

            if (type.IsEnum || type.IsInterface || type.IsValueType)
            {
                Diagnostic.Error(4200, LookupSource(type), Localization.Resources.JavaCallableWrappers_XA4200, type.FullName);
            }

            string jniName = JavaNativeTypeManager.ToJniName(type);

            if (jniName == null)
            {
                Diagnostic.Error(4201, LookupSource(type), Localization.Resources.JavaCallableWrappers_XA4201, type.FullName);
            }
            if (!string.IsNullOrEmpty(outerType))
            {
                string p;
                jniName = jniName.Substring(outerType.Length + 1);
                ExtractJavaNames(outerType, out p, out outerType);
            }
            ExtractJavaNames(jniName, out package, out name);
            if (string.IsNullOrEmpty(package) &&
                (type.IsSubclassOf("Android.App.Activity", cache) ||
                 type.IsSubclassOf("Android.App.Application", cache) ||
                 type.IsSubclassOf("Android.App.Service", cache) ||
                 type.IsSubclassOf("Android.Content.BroadcastReceiver", cache) ||
                 type.IsSubclassOf("Android.Content.ContentProvider", cache)))
            {
                Diagnostic.Error(4203, LookupSource(type), Localization.Resources.JavaCallableWrappers_XA4203, jniName);
            }

            foreach (MethodDefinition minfo in type.Methods.Where(m => !m.IsConstructor))
            {
                var baseRegisteredMethod = GetBaseRegisteredMethod(minfo);
                if (baseRegisteredMethod != null)
                {
                    AddMethod(baseRegisteredMethod, minfo);
                }
                else if (GetExportFieldAttributes(minfo).Any())
                {
                    AddMethod(null, minfo);
                    HasExport = true;
                }
                else if (GetExportAttributes(minfo).Any())
                {
                    AddMethod(null, minfo);
                    HasExport = true;
                }
            }

            foreach (MethodDefinition imethod in type.Interfaces.Select(ifaceInfo => ifaceInfo.InterfaceType)
                     .Select(r => {
                var d = r.Resolve();
                if (d == null)
                {
                    Diagnostic.Error(4204,
                                     LookupSource(type),
                                     Localization.Resources.JavaCallableWrappers_XA4204,
                                     r.FullName);
                }
                return(d);
            })
                     .Where(d => GetRegisterAttributes(d).Any())
                     .SelectMany(d => d.Methods)
                     .Where(m => !m.IsStatic))
            {
                AddMethod(imethod, imethod);
            }

            var ctorTypes = new List <TypeDefinition> ()
            {
                type,
            };

            foreach (var bt in type.GetBaseTypes(cache))
            {
                ctorTypes.Add(bt);
                RegisterAttribute rattr = GetRegisterAttributes(bt).FirstOrDefault();
                if (rattr != null && rattr.DoNotGenerateAcw)
                {
                    break;
                }
            }
            ctorTypes.Reverse();

            var curCtors = new List <MethodDefinition> ();

            foreach (MethodDefinition minfo in type.Methods.Where(m => m.IsConstructor))
            {
                if (GetExportAttributes(minfo).Any())
                {
                    if (minfo.IsStatic)
                    {
                        // Diagnostic.Warning (log, "ExportAttribute does not work on static constructor");
                    }
                    else
                    {
                        AddConstructor(minfo, ctorTypes [0], outerType, null, curCtors, false, true);
                        HasExport = true;
                    }
                }
            }

            AddConstructors(ctorTypes [0], outerType, null, curCtors, true);

            for (int i = 1; i < ctorTypes.Count; ++i)
            {
                var baseCtors = curCtors;
                curCtors = new List <MethodDefinition> ();
                AddConstructors(ctorTypes [i], outerType, baseCtors, curCtors, false);
            }
        }
예제 #17
0
 static string GetJniSignature(MethodDefinition ctor)
 {
     return(JavaNativeTypeManager.GetJniSignature(ctor));
 }
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseCrc64;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                if (bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {assembly.ItemSpec}");
                    continue;
                }
                res.Load(assembly.ItemSpec);
            }

            // However we only want to look for JLO types in user code
            List <string> assemblies = new List <string> ();

            foreach (var asm in ResolvedUserAssemblies)
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}");
                    continue;
                }
                if (!assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(asm.ItemSpec)))
                {
                    continue;
                }
                Log.LogDebugMessage($"Adding {asm.ItemSpec} to assemblies.");
                assemblies.Add(asm.ItemSpec);
            }
            foreach (var asm in MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies))
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}");
                    continue;
                }
                if (!assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(asm.ItemSpec)))
                {
                    continue;
                }
                Log.LogDebugMessage($"Adding {asm.ItemSpec} to assemblies.");
                assemblies.Add(asm.ItemSpec);
            }

            // Step 1 - Find all the JLO types
            var scanner = new JavaTypeScanner(this.CreateTaskLogger())
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };
            var all_java_types = scanner.GetJavaTypes(assemblies, res);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types
                             .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t))
                             .ToArray();

            // Step 2 - Generate Java stub code
            var success = Generator.CreateJavaSources(
                Log,
                java_types,
                Path.Combine(OutputDirectory, "src"),
                ApplicationJavaClass,
                AndroidSdkPlatform,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);

            var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);
            var javaConflicts    = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);

            // Allocate a MemoryStream with a reasonable guess at its capacity
            using (var stream = new MemoryStream(java_types.Length * 32))
                using (var acw_map = new StreamWriter(stream)) {
                    foreach (var type in java_types)
                    {
                        string managedKey = type.FullName.Replace('/', '.');
                        string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                        acw_map.Write(type.GetPartialAssemblyQualifiedName());
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        TypeDefinition conflict;
                        bool           hasConflict = false;
                        if (managed.TryGetValue(managedKey, out conflict))
                        {
                            if (!managedConflicts.TryGetValue(managedKey, out var list))
                            {
                                managedConflicts.Add(managedKey, list = new List <string> {
                                    conflict.GetPartialAssemblyName()
                                });
                            }
                            list.Add(type.GetPartialAssemblyName());
                            hasConflict = true;
                        }
                        if (java.TryGetValue(javaKey, out conflict))
                        {
                            if (!javaConflicts.TryGetValue(javaKey, out var list))
                            {
                                javaConflicts.Add(javaKey, list = new List <string> {
                                    conflict.GetAssemblyQualifiedName()
                                });
                            }
                            list.Add(type.GetAssemblyQualifiedName());
                            success     = false;
                            hasConflict = true;
                        }
                        if (!hasConflict)
                        {
                            managed.Add(managedKey, type);
                            java.Add(javaKey, type);

                            acw_map.Write(managedKey);
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();

                            acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'));
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();
                        }
                    }

                    acw_map.Flush();
                    MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile);
                }

            foreach (var kvp in managedConflicts)
            {
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214, kvp.Key, string.Join(", ", kvp.Value));
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214_Result, kvp.Key, kvp.Value [0]);
            }

            foreach (var kvp in javaConflicts)
            {
                Log.LogCodedError(
                    "XA4215",
                    "The Java type `{0}` is generated by more than one managed type. " +
                    "Please change the [Register] attribute so that the same Java type is not emitted.",
                    kvp.Key);
                foreach (var typeName in kvp.Value)
                {
                    Log.LogCodedError("XA4215", "  `{0}` generated by: {1}", kvp.Key, typeName);
                }
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(all_java_types, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName);

            using (var stream = new MemoryStream()) {
                manifest.Save(stream);

                // Only write the new manifest if it actually changed
                MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput);
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource(providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));
        }
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseCrc64;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            // Put every assembly we'll need in the resolver
            bool hasExportReference   = false;
            bool haveMonoAndroid      = false;
            var  allTypemapAssemblies = new HashSet <string> (StringComparer.OrdinalIgnoreCase);
            var  userAssemblies       = new Dictionary <string, string> (StringComparer.OrdinalIgnoreCase);

            foreach (var assembly in ResolvedAssemblies)
            {
                bool value;
                if (bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {assembly.ItemSpec}");
                    continue;
                }

                bool   addAssembly = false;
                string fileName    = Path.GetFileName(assembly.ItemSpec);
                if (!hasExportReference && String.Compare("Mono.Android.Export.dll", fileName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    hasExportReference = true;
                    addAssembly        = true;
                }
                else if (!haveMonoAndroid && String.Compare("Mono.Android.dll", fileName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    haveMonoAndroid = true;
                    addAssembly     = true;
                }
                else if (MonoAndroidHelper.FrameworkAssembliesToTreatAsUserAssemblies.Contains(fileName))
                {
                    if (!bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out value) || !value)
                    {
                        string name = Path.GetFileNameWithoutExtension(fileName);
                        if (!userAssemblies.ContainsKey(name))
                        {
                            userAssemblies.Add(name, assembly.ItemSpec);
                        }
                        addAssembly = true;
                    }
                }

                if (addAssembly)
                {
                    allTypemapAssemblies.Add(assembly.ItemSpec);
                }

                res.Load(assembly.ItemSpec);
            }

            // However we only want to look for JLO types in user code for Java stub code generation
            foreach (var asm in ResolvedUserAssemblies)
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}");
                    continue;
                }
                allTypemapAssemblies.Add(asm.ItemSpec);
                userAssemblies.Add(Path.GetFileNameWithoutExtension(asm.ItemSpec), asm.ItemSpec);
            }

            // Step 1 - Find all the JLO types
            var cache   = new TypeDefinitionCache();
            var scanner = new JavaTypeScanner(this.CreateTaskLogger(), cache)
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };

            List <TypeDefinition> allJavaTypes = scanner.GetJavaTypes(allTypemapAssemblies, res);

            // Step 2 - Generate type maps
            //   Type mappings need to use all the assemblies, always.
            WriteTypeMappings(allJavaTypes);

            var javaTypes = new List <TypeDefinition> ();

            foreach (TypeDefinition td in allJavaTypes)
            {
                if (!userAssemblies.ContainsKey(td.Module.Assembly.Name.Name) || JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(td, cache))
                {
                    continue;
                }

                javaTypes.Add(td);
            }

            // Step 3 - Generate Java stub code
            var success = CreateJavaSources(javaTypes, cache);

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (javaTypes.Count, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (javaTypes.Count, StringComparer.Ordinal);

            var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);
            var javaConflicts    = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);

            using (var acw_map = MemoryStreamPool.Shared.CreateStreamWriter(Encoding.Default)) {
                foreach (TypeDefinition type in javaTypes)
                {
                    string managedKey = type.FullName.Replace('/', '.');
                    string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                    acw_map.Write(type.GetPartialAssemblyQualifiedName(cache));
                    acw_map.Write(';');
                    acw_map.Write(javaKey);
                    acw_map.WriteLine();

                    TypeDefinition conflict;
                    bool           hasConflict = false;
                    if (managed.TryGetValue(managedKey, out conflict))
                    {
                        if (!managedConflicts.TryGetValue(managedKey, out var list))
                        {
                            managedConflicts.Add(managedKey, list = new List <string> {
                                conflict.GetPartialAssemblyName(cache)
                            });
                        }
                        list.Add(type.GetPartialAssemblyName(cache));
                        hasConflict = true;
                    }
                    if (java.TryGetValue(javaKey, out conflict))
                    {
                        if (!javaConflicts.TryGetValue(javaKey, out var list))
                        {
                            javaConflicts.Add(javaKey, list = new List <string> {
                                conflict.GetAssemblyQualifiedName(cache)
                            });
                        }
                        list.Add(type.GetAssemblyQualifiedName(cache));
                        success     = false;
                        hasConflict = true;
                    }
                    if (!hasConflict)
                    {
                        managed.Add(managedKey, type);
                        java.Add(javaKey, type);

                        acw_map.Write(managedKey);
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type, cache).Replace('/', '.'));
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();
                    }
                }

                acw_map.Flush();
                MonoAndroidHelper.CopyIfStreamChanged(acw_map.BaseStream, AcwMapFile);
            }

            foreach (var kvp in managedConflicts)
            {
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214, kvp.Key, string.Join(", ", kvp.Value));
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214_Result, kvp.Key, kvp.Value [0]);
            }

            foreach (var kvp in javaConflicts)
            {
                Log.LogCodedError("XA4215", Properties.Resources.XA4215, kvp.Key);
                foreach (var typeName in kvp.Value)
                {
                    Log.LogCodedError("XA4215", Properties.Resources.XA4215_Details, kvp.Key, typeName);
                }
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(userAssemblies.Values);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(Log, cache, allJavaTypes, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            // Only write the new manifest if it actually changed
            if (manifest.SaveIfChanged(Log, MergedAndroidManifestOutput))
            {
                Log.LogDebugMessage($"Saving: {MergedAndroidManifestOutput}");
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource(providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in javaTypes)
            {
                if (JavaNativeTypeManager.IsApplication(type, cache) || JavaNativeTypeManager.IsInstrumentation(type, cache))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(cache), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));
        }
예제 #20
0
 public void Crc64()
 {
     JavaNativeTypeManager.PackageNamingPolicy = PackageNamingPolicy.LowercaseCrc64;
     Assert.AreEqual("crc64b74743e9328eed0a", JavaNativeTypeManager.GetPackageName(typeof(string)));
 }