public override bool Execute()
        {
            // If we don't have a manifest, default to using the assembly name
            // If the assembly doesn't have a period in it, duplicate it so it does
            PackageName = AndroidAppManifest.CanonicalizePackageName(AssemblyName);

            if (string.IsNullOrEmpty(ManifestFile) || !File.Exists(ManifestFile))
            {
                Log.LogMessage("  PackageName: {0}", PackageName);
                return(true);
            }

            XmlDocument doc = new XmlDocument();

            doc.Load(ManifestFile);

            if (!doc.DocumentElement.HasAttribute("package"))
            {
                Log.LogMessage("  PackageName: {0}", PackageName);
                return(true);
            }

            PackageName = AndroidAppManifest.CanonicalizePackageName(doc.DocumentElement.GetAttribute("package"));

            Log.LogMessage("  PackageName: {0}", PackageName);

            return(true);
        }
示例#2
0
        public override bool RunTask()
        {
            if (!string.IsNullOrEmpty(PackageName))
            {
                PackageName = AndroidAppManifest.CanonicalizePackageName(PackageName);
            }
            else if (!string.IsNullOrEmpty(ManifestFile) && File.Exists(ManifestFile))
            {
                using var stream = File.OpenRead(ManifestFile);
                using var reader = XmlReader.Create(stream);
                if (reader.MoveToContent() == XmlNodeType.Element)
                {
                    var package = reader.GetAttribute("package");
                    if (!string.IsNullOrEmpty(package))
                    {
                        package     = ManifestDocument.ReplacePlaceholders(ManifestPlaceholders, package);
                        PackageName = AndroidAppManifest.CanonicalizePackageName(package);
                    }
                }
            }

            // If we don't have a manifest, default to using the assembly name
            // If the assembly doesn't have a period in it, duplicate it so it does
            if (string.IsNullOrEmpty(PackageName))
            {
                PackageName = AndroidAppManifest.CanonicalizePackageName(AssemblyName);
            }

            Log.LogDebugMessage($"  PackageName: {PackageName}");

            return(!Log.HasLoggedErrors);
        }
        public override bool Execute()
        {
            if (ProjectFiles.Length != 1)
            {
                Log.LogError("More than one Android Wear project is specified as the paired project. It can be at most one.");
            }

            var wearProj    = ProjectFiles.First();
            var manifestXml = XDocument.Load(wearProj.ItemSpec)
                              .Root.Elements(msbuildNS + "PropertyGroup").Elements(msbuildNS + "AndroidManifest").Select(e => e.Value).FirstOrDefault();

            if (string.IsNullOrEmpty(manifestXml))
            {
                Log.LogError("Target Wear application's project '{0}' does not specify required 'AndroidManifest' project property.", wearProj);
            }
            manifestXml = Path.Combine(Path.GetDirectoryName(wearProj.ItemSpec), manifestXml.Replace('\\', Path.DirectorySeparatorChar));

            ApplicationManifestFile = manifestXml;

            Log.LogDebugMessage("  [Output] ApplicationManifestFile: " + ApplicationManifestFile);

            ApplicationPackageName = AndroidAppManifest.CanonicalizePackageName(XDocument.Load(manifestXml).Root.Attributes("package").Select(a => a.Value).FirstOrDefault());
            if (string.IsNullOrEmpty(ApplicationPackageName))
            {
                Log.LogError("Target Wear application's AndroidManifest.xml does not specify required 'package' attribute.");
            }

            Log.LogDebugMessage("  [Output] ApplicationPackageName: " + ApplicationPackageName);
            return(true);
        }
示例#4
0
        public override bool RunTask()
        {
            if (ProjectFiles.Length != 1)
            {
                Log.LogCodedError("XA1015", Properties.Resources.XA1015);
            }

            var wearProj    = ProjectFiles.First();
            var manifestXml = XDocument.Load(wearProj.ItemSpec)
                              .Root.Elements(msbuildNS + "PropertyGroup").Elements(msbuildNS + "AndroidManifest").Select(e => e.Value).FirstOrDefault();

            if (string.IsNullOrEmpty(manifestXml))
            {
                Log.LogCodedError("XA1016", Properties.Resources.XA1016, wearProj);
            }
            manifestXml = Path.Combine(Path.GetDirectoryName(wearProj.ItemSpec), manifestXml.Replace('\\', Path.DirectorySeparatorChar));

            ApplicationManifestFile = manifestXml;

            Log.LogDebugMessage("  [Output] ApplicationManifestFile: " + ApplicationManifestFile);

            ApplicationPackageName = AndroidAppManifest.CanonicalizePackageName(XDocument.Load(manifestXml).Root.Attributes("package").Select(a => a.Value).FirstOrDefault());
            if (string.IsNullOrEmpty(ApplicationPackageName))
            {
                Log.LogCodedError("XA1017", Properties.Resources.XA1017);
            }

            Log.LogDebugMessage("  [Output] ApplicationPackageName: " + ApplicationPackageName);
            return(true);
        }
示例#5
0
        public override bool RunTask()
        {
            string rawapk = "wearable_app.apk";
            string intermediateApkPath = Path.Combine(IntermediateOutputPath, "res", "raw", rawapk);
            string intermediateXmlFile = Path.Combine(IntermediateOutputPath, "res", "xml", "wearable_app_desc.xml");

            var doc             = XDocument.Load(WearAndroidManifestFile);
            var wearPackageName = AndroidAppManifest.CanonicalizePackageName(doc.Root.Attribute("package").Value);
            var modified        = new List <string> ();

            if (PackageName != wearPackageName)
            {
                Log.LogCodedError("XA5211", Properties.Resources.XA5211, wearPackageName, PackageName);
            }

            if (!File.Exists(WearApplicationApkPath))
            {
                Log.LogWarning("This application won't contain the paired Wear package because the Wear application package .apk is not created yet. If you are using MSBuild or XBuild, you have to invoke \"SignAndroidPackage\" target.");
                return(true);
            }

            var xml = string.Format(@"<wearableApp package=""{0}"">
  <versionCode>{1}</versionCode>
  <versionName>{2}</versionName>
  <rawPathResId>{3}</rawPathResId>
</wearableApp>
", wearPackageName, doc.Root.Attribute(androidNs + "versionCode").Value, doc.Root.Attribute(androidNs + "versionName").Value, Path.GetFileNameWithoutExtension(rawapk));

            if (MonoAndroidHelper.CopyIfChanged(WearApplicationApkPath, intermediateApkPath))
            {
                Log.LogDebugMessage("    Copied APK to {0}", intermediateApkPath);
                modified.Add(intermediateApkPath);
            }

            Directory.CreateDirectory(Path.GetDirectoryName(intermediateXmlFile));
            if (!File.Exists(intermediateXmlFile) || !XDocument.DeepEquals(XDocument.Load(intermediateXmlFile), XDocument.Parse(xml)))
            {
                File.WriteAllText(intermediateXmlFile, xml);
                Log.LogDebugMessage("    Created additional resource as {0}", intermediateXmlFile);
                modified.Add(intermediateXmlFile);
            }
            WearableApplicationDescriptionFile = new TaskItem(intermediateXmlFile);
            WearableApplicationDescriptionFile.SetMetadata("_FlatFile", Monodroid.AndroidResource.CalculateAapt2FlatArchiveFileName(intermediateXmlFile));
            WearableApplicationDescriptionFile.SetMetadata("_ArchiveDirectory", AndroidLibraryFlatFilesDirectory);
            WearableApplicationDescriptionFile.SetMetadata("IsWearApplicationResource", "True");
            BundledWearApplicationApkResourceFile = new TaskItem(intermediateApkPath);
            BundledWearApplicationApkResourceFile.SetMetadata("_FlatFile", Monodroid.AndroidResource.CalculateAapt2FlatArchiveFileName(intermediateApkPath));
            BundledWearApplicationApkResourceFile.SetMetadata("_ArchiveDirectory", AndroidLibraryFlatFilesDirectory);
            BundledWearApplicationApkResourceFile.SetMetadata("IsWearApplicationResource", "True");
            ModifiedFiles = modified.ToArray();

            return(true);
        }
        public override bool Execute()
        {
            Log.LogDebugMessage("PrepareWearApplicationFiles task");
            Log.LogDebugTaskItems("  WearAndroidManifestFile:", WearAndroidManifestFile);
            Log.LogDebugTaskItems("  IntermediateOutputPath:", IntermediateOutputPath);
            Log.LogDebugTaskItems("  WearApplicationApkPath:", WearApplicationApkPath);

            string rawapk = "wearable_app.apk";
            string intermediateApkPath = Path.Combine(IntermediateOutputPath, "res", "raw", rawapk);
            string intermediateXmlFile = Path.Combine(IntermediateOutputPath, "res", "xml", "wearable_app_desc.xml");

            var doc             = XDocument.Load(WearAndroidManifestFile);
            var wearPackageName = AndroidAppManifest.CanonicalizePackageName(doc.Root.Attribute("package").Value);

            if (PackageName != wearPackageName)
            {
                Log.LogCodedError("XA5211", "Embedded wear app package name differs from handheld app package name ({0} != {1}).", wearPackageName, PackageName);
            }

            if (!File.Exists(WearApplicationApkPath))
            {
                Log.LogWarning("This application won't contain the paired Wear package because the Wear application package .apk is not created yet. If you are using MSBuild or XBuild, you have to invoke \"SignAndroidPackage\" target.");
                return(true);
            }

            var xml = string.Format(@"<wearableApp package=""{0}"">
  <versionCode>{1}</versionCode>
  <versionName>{2}</versionName>
  <rawPathResId>{3}</rawPathResId>
</wearableApp>
", wearPackageName, doc.Root.Attribute(androidNs + "versionCode").Value, doc.Root.Attribute(androidNs + "versionName").Value, Path.GetFileNameWithoutExtension(rawapk));

            MonoAndroidHelper.CopyIfChanged(WearApplicationApkPath, intermediateApkPath);

            Directory.CreateDirectory(Path.GetDirectoryName(intermediateXmlFile));
            if (!File.Exists(intermediateXmlFile) || !XDocument.DeepEquals(XDocument.Load(intermediateXmlFile), XDocument.Parse(xml)))
            {
                File.WriteAllText(intermediateXmlFile, xml);
                Log.LogDebugMessage("    Created additional resource as {0}", intermediateXmlFile);
            }
            WearableApplicationDescriptionFile = new TaskItem(intermediateXmlFile);
            WearableApplicationDescriptionFile.SetMetadata("IsWearApplicationResource", "True");
            BundledWearApplicationApkResourceFile = new TaskItem(intermediateApkPath);
            BundledWearApplicationApkResourceFile.SetMetadata("IsWearApplicationResource", "True");

            return(true);
        }
示例#7
0
        public void CanonicalizePackageName()
        {
            Assert.Throws <ArgumentNullException>(() => AndroidAppManifest.CanonicalizePackageName(null));
            Assert.Throws <ArgumentException>(() => AndroidAppManifest.CanonicalizePackageName(""));
            Assert.Throws <ArgumentException>(() => AndroidAppManifest.CanonicalizePackageName("  "));

            Assert.AreEqual("A.A",
                            AndroidAppManifest.CanonicalizePackageName("A"));
            Assert.AreEqual("Foo.Bar",
                            AndroidAppManifest.CanonicalizePackageName("Foo.Bar"));
            Assert.AreEqual("foo_bar.foo_bar",
                            AndroidAppManifest.CanonicalizePackageName("foo-bar"));
            Assert.AreEqual("x1.x1",
                            AndroidAppManifest.CanonicalizePackageName("1"));
            Assert.AreEqual("x_1.x_2",
                            AndroidAppManifest.CanonicalizePackageName("_1._2"));
            Assert.AreEqual("mfa1.x0.x2_2",
                            AndroidAppManifest.CanonicalizePackageName("mfa1.0.2_2"));
            Assert.AreEqual("My.Cool_Assembly",
                            AndroidAppManifest.CanonicalizePackageName("My.Cool Assembly"));
            Assert.AreEqual("x7Cats.x7Cats",
                            AndroidAppManifest.CanonicalizePackageName("7Cats"));
        }
        public IList <string> Merge(List <TypeDefinition> subclasses, 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);

            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);

            if (mergedManifestDocuments != null)
            {
                foreach (var mergedManifest in mergedManifestDocuments)
                {
                    try {
                        MergeLibraryManifest(mergedManifest);
                    } catch (Exception ex) {
                        log.LogCodedWarning("XA4302", "Unhandled exception merging `AndroidManifest.xml`: {0}", ex);
                    }
                }
            }

            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);
            }
        }
示例#9
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 targetSdkVersionValue;

            if (!int.TryParse(MonoAndroidHelper.GetPlatformApiLevel(targetSdkVersion), out targetSdkVersionValue))
            {
                throw new InvalidOperationException(string.Format("The targetSdkVersion ({0}) is not a valid API level", targetSdkVersion));
            }

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

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

                var name       = JniType.ToJniName(t).Replace('/', '.');
                var compatName = JniType.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);
        }