From 231464544675a74e7f961cb41952bf17769bf19b Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 4 Aug 2023 15:37:14 -0400 Subject: [PATCH] [Xamarin.Android.Tools.AndroidSdk] Check all s Context: https://developercommunity.visualstudio.com/t/Cannot-deploy-to-Android-emulators-and-d/10428163 Context: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1863835 Context: https://developer.android.com/guide/components/intents-filters The [``][0] and related elements within `AndroidManifest.xml` can have multiple [``][1]s specified. Android does not require that ``s be listed in any particular order. However, Visual Studio *does* care about the order (?!)! [Activity(Exported = true, Label = "@string/app_name", MainLauncher = true)] [IntentFilter( new[] { Android.Content.Intent.ActionView }, Categories = new[] { Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable, } )] [IntentFilter( new[] { Android.Content.Intent.ActionMain }, Categories = new[] { Android.Content.Intent.CategoryLauncher, Android.Content.Intent.CategoryLeanbackLauncher, } )] public partial class MainActivity : Activity {} If the `[IntentFilter]` with `Android.Content.Intent.ActionMain` is *not* first, then Visual Studio does not consider this Activity to be a launchable activity. The reason for this is, in part, because `AndroidAppManifest.GetLaunchableActivities()` only looked at the *first* `` to see if it had the category of `android.intent.category.LAUNCHER`. Update `AndroidAppManifest.GetLaunchableActivities()` so that *all* `` elements are checked for the `.LAUNCHER` category. **Workaround**: Specify the `[IntentFilter]` with `Intent.ActionMain` first: [Activity(Exported = true, Label = "@string/app_name", MainLauncher = true)] [IntentFilter( new[] { Android.Content.Intent.ActionMain }, Categories = new[] { Android.Content.Intent.CategoryLauncher, Android.Content.Intent.CategoryLeanbackLauncher, } )] [IntentFilter( new[] { Android.Content.Intent.ActionView }, Categories = new[] { Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable, } )] public partial class MainActivity : Activity {} Note: this change, in and of itself, may not be sufficient to fix Visual Studio, as there are a few other places that have the same "only check the first ``" bug. [0]: https://developer.android.com/guide/topics/manifest/activity-element [1]: https://developer.android.com/guide/topics/manifest/intent-filter-element --- .../AndroidAppManifest.cs | 3 +-- .../AndroidAppManifestTests.cs | 10 ++++++++++ .../Resources/manifest-simplewidget.xml | 11 +++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs b/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs index 5ef7e13..7ba12c9 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs @@ -323,8 +323,7 @@ void RemoveAndroidPermissions (IEnumerable permissions) IEnumerable GetLaunchableActivities () { foreach (var activity in application.Elements ("activity")) { - var filter = activity.Element ("intent-filter"); - if (filter != null) { + foreach (var filter in activity.Elements ("intent-filter")) { foreach (var category in filter.Elements ("category")) if (category != null && (string?)category.Attribute (aName) == "android.intent.category.LAUNCHER") yield return activity; diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidAppManifestTests.cs b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidAppManifestTests.cs index c387ce2..243224d 100644 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidAppManifestTests.cs +++ b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidAppManifestTests.cs @@ -45,6 +45,16 @@ static XDocument GetTestAppManifest () } } + [Test] + public void GetLaunchableActivityNames () + { + var versions = new AndroidVersions (Array.Empty()); + var manifest = AndroidAppManifest.Load (GetTestAppManifest (), versions); + var launchers = manifest.GetLaunchableActivityNames ().ToList (); + Assert.AreEqual (1, launchers.Count); + Assert.AreEqual (".HasMultipleIntentFilters", launchers [0]); + } + [Test] public void SetNewPermissions () { diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Resources/manifest-simplewidget.xml b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Resources/manifest-simplewidget.xml index 966639d..c834c6c 100644 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Resources/manifest-simplewidget.xml +++ b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Resources/manifest-simplewidget.xml @@ -22,6 +22,17 @@ + + + + + + + + + + +