Skip to content

Commit

Permalink
[Mono.Android] [IntentFilter] pathSuffix & pathAdvancedPattern (#8261)
Browse files Browse the repository at this point in the history
Fixes: #8235

Context: #8272

Add the following properties to `IntentFilterAttribute` to allow
the various `AndroidManifest.xml` [`<data/>`][0] attributes to
be generated:

  - `IntentFilterAttribute.DataPathSuffix` generates
    [`//intent-filter/data/@pathSuffix`][1].
  - `IntentFilterAttribute.DataPathSuffixes` generates
    [`//intent-filter/data/@pathSuffix`][1].
  - `IntentFilterAttribute.DataPathAdvancedPattern` generates
    [`//intent-filter/data/@pathAdvancedPattern`][1].
  - `IntentFilterAttribute.DataPathAdvancedPatterns` generates
    [`//intent-filter/data/@pathAdvancedPattern`][1].

Note that while we have a script to detect new elements added to
`AndroidManifest.xml`, the code must be written manually.

TODO: Issue #8272 to automate this code generation.

[0]: https://developer.android.com/guide/topics/manifest/data-element
[1]: https://developer.android.com/guide/topics/manifest/data-element#path
  • Loading branch information
jpobst authored and jonathanpeppers committed Aug 22, 2023
1 parent 75fc6f3 commit 5a1b9b1
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@
<a name='sspPrefix' format='string' api-level='19' />
<a name='sspPattern' format='string' api-level='19' />
<a name='pathAdvancedPattern' api-level='26' />
<a name='pathSuffix' api-level='31' />
</e>
<e name='category'>
<parent>intent-filter</parent>
Expand Down
8 changes: 8 additions & 0 deletions src/Mono.Android/Android.App/IntentFilterAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ public IntentFilterAttribute (string[] actions)
#endif
#if ANDROID_25
public string? RoundIcon {get; set;}
#endif
#if ANDROID_26
public string? DataPathAdvancedPattern {get; set;}
public string[]? DataPathAdvancedPatterns {get; set;}
#endif
#if ANDROID_31
public string? DataPathSuffix {get; set;}
public string[]? DataPathSuffixes {get; set;}
#endif
}
}
8 changes: 8 additions & 0 deletions src/Mono.Android/PublicAPI/API-34/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5215,6 +5215,10 @@ Android.App.IntentFilterAttribute.DataMimeTypes.get -> string![]?
Android.App.IntentFilterAttribute.DataMimeTypes.set -> void
Android.App.IntentFilterAttribute.DataPath.get -> string?
Android.App.IntentFilterAttribute.DataPath.set -> void
Android.App.IntentFilterAttribute.DataPathAdvancedPattern.get -> string?
Android.App.IntentFilterAttribute.DataPathAdvancedPattern.set -> void
Android.App.IntentFilterAttribute.DataPathAdvancedPatterns.get -> string![]?
Android.App.IntentFilterAttribute.DataPathAdvancedPatterns.set -> void
Android.App.IntentFilterAttribute.DataPathPattern.get -> string?
Android.App.IntentFilterAttribute.DataPathPattern.set -> void
Android.App.IntentFilterAttribute.DataPathPatterns.get -> string![]?
Expand All @@ -5225,6 +5229,10 @@ Android.App.IntentFilterAttribute.DataPathPrefixes.get -> string![]?
Android.App.IntentFilterAttribute.DataPathPrefixes.set -> void
Android.App.IntentFilterAttribute.DataPaths.get -> string![]?
Android.App.IntentFilterAttribute.DataPaths.set -> void
Android.App.IntentFilterAttribute.DataPathSuffix.get -> string?
Android.App.IntentFilterAttribute.DataPathSuffix.set -> void
Android.App.IntentFilterAttribute.DataPathSuffixes.get -> string![]?
Android.App.IntentFilterAttribute.DataPathSuffixes.set -> void
Android.App.IntentFilterAttribute.DataPort.get -> string?
Android.App.IntentFilterAttribute.DataPort.set -> void
Android.App.IntentFilterAttribute.DataPorts.get -> string![]?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ partial class IntentFilterAttribute {
{ "DataPort", "port" },
{ "DataScheme", "scheme" },
{ "AutoVerify", "autoVerify" },
{ "DataPathSuffix", "pathSuffix" },
{ "DataPathAdvancedPattern", "pathAdvancedPattern" },
};

static readonly Dictionary<string, Action<IntentFilterAttribute, object>> setters = new Dictionary<string, Action<IntentFilterAttribute, object>> () {
Expand All @@ -50,6 +52,10 @@ partial class IntentFilterAttribute {
{ "DataSchemes", (self, value) => self.DataSchemes = ToStringArray (value) },
{ "AutoVerify", (self, value) => self._AutoVerify = (bool) value },
{ "RoundIcon", (self, value) => self._RoundIcon = (string) value },
{ "DataPathSuffix", (self, value) => self.DataPathSuffix = (string) value },
{ "DataPathSuffixes", (self, value) => self.DataPathSuffixes = ToStringArray (value) },
{ "DataPathAdvancedPattern", (self, value) => self.DataPathAdvancedPattern = (string) value },
{ "DataPathAdvancedPatterns", (self, value) => self.DataPathAdvancedPatterns = ToStringArray (value) },
};

static string[] ToStringArray (object value)
Expand Down Expand Up @@ -126,6 +132,8 @@ IEnumerable<XElement> GetData (string packageName)
Func<string,XAttribute> toPathPrefix = v => ToAttribute ("DataPathPrefix", ReplacePackage (v, packageName));
Func<string,XAttribute> toPort = v => ToAttribute ("DataPort", ReplacePackage (v, packageName));
Func<string,XAttribute> toScheme = v => ToAttribute ("DataScheme", ReplacePackage (v, packageName));
Func<string,XAttribute> toPathSuffix = v => ToAttribute ("DataPathSuffix", ReplacePackage (v, packageName));
Func<string,XAttribute> toPathAdvancedPattern = v => ToAttribute ("DataPathAdvancedPattern", ReplacePackage (v, packageName));
Func<Func<string,XAttribute>, string, XElement> toData = (f, s) => string.IsNullOrEmpty (s) ? null : new XElement ("data", f (s));
var empty = Array.Empty<string> ();
var dataList = Enumerable.Empty<XElement> ()
Expand All @@ -135,11 +143,13 @@ IEnumerable<XElement> GetData (string packageName)
.Concat ((DataPathPatterns ?? empty).Select (p => toData (toPathPattern, p)))
.Concat ((DataPathPrefixes ?? empty).Select (p => toData (toPathPrefix, p)))
.Concat ((DataPorts ?? empty).Select (p => toData (toPort, p)))
.Concat ((DataSchemes ?? empty).Select (p => toData (toScheme, p)));
.Concat ((DataSchemes ?? empty).Select (p => toData (toScheme, p)))
.Concat ((DataPathSuffixes ?? empty).Select (p => toData (toPathSuffix, p)))
.Concat ((DataPathAdvancedPatterns ?? empty).Select (p => toData (toPathAdvancedPattern, p)));
if (string.IsNullOrEmpty (DataHost) && string.IsNullOrEmpty (DataMimeType) &&
string.IsNullOrEmpty (DataPath) && string.IsNullOrEmpty (DataPathPattern) && string.IsNullOrEmpty (DataPathPrefix) &&
string.IsNullOrEmpty (DataPort) && string.IsNullOrEmpty (DataScheme) &&
!dataList.Any ())
string.IsNullOrEmpty (DataPort) && string.IsNullOrEmpty (DataScheme) && string.IsNullOrEmpty (DataPathSuffix) &&
string.IsNullOrEmpty (DataPathAdvancedPattern) && !dataList.Any ())
return null;
return new XElement [] {
toData (toHost, DataHost),
Expand All @@ -148,7 +158,9 @@ IEnumerable<XElement> GetData (string packageName)
toData (toPathPattern, DataPathPattern),
toData (toPathPrefix, DataPathPrefix),
toData (toPort, DataPort),
toData (toScheme, DataScheme) }
toData (toScheme, DataScheme),
toData (toPathSuffix, DataPathSuffix),
toData (toPathAdvancedPattern, DataPathAdvancedPattern)}
.Concat (dataList).Where (x => x != null);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
using System.Collections.Generic;
using Xamarin.Android.Tasks;
using Xamarin.Android.Tools;
using Android.App;
using Mono.Cecil;
using System.Reflection;

namespace Xamarin.Android.Build.Tests
{
Expand Down Expand Up @@ -1118,5 +1121,53 @@ public void SupportedOSPlatformVersionErrors (string minSdkVersion, string suppo
}
}

[IntentFilter (new [] { "singularAction" },
DataPathSuffix = "singularSuffix",
DataPathAdvancedPattern = "singularPattern")]
[IntentFilter (new [] { "pluralAction" },
DataPathSuffixes = new [] { "pluralSuffix1", "pluralSuffix2" },
DataPathAdvancedPatterns = new [] { "pluralPattern1", "pluralPattern2" })]

public class IntentFilterAttributeDataPathTestClass { }

[Test]
public void IntentFilterDataPathTest ()
{
var asm = AssemblyDefinition.ReadAssembly (typeof (IntentFilterAttributeDataPathTestClass).Assembly.Location);
var type = asm.MainModule.GetType ("Xamarin.Android.Build.Tests.ManifestTest/IntentFilterAttributeDataPathTestClass");

var intent = IntentFilterAttribute.FromTypeDefinition (type).Single (f => f.Actions.Contains ("singularAction"));
var xml = intent.ToElement ("dummy.packageid").ToString ();

var expected =
@"<intent-filter>
<action p2:name=""singularAction"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
<data p2:pathSuffix=""singularSuffix"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
<data p2:pathAdvancedPattern=""singularPattern"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
</intent-filter>";

StringAssertEx.AreMultiLineEqual (expected, xml);
}

[Test]
public void IntentFilterDataPathsTest ()
{
var asm = AssemblyDefinition.ReadAssembly (typeof (IntentFilterAttributeDataPathTestClass).Assembly.Location);
var type = asm.MainModule.GetType ("Xamarin.Android.Build.Tests.ManifestTest/IntentFilterAttributeDataPathTestClass");

var intent = IntentFilterAttribute.FromTypeDefinition (type).Single (f => f.Actions.Contains ("pluralAction"));
var xml = intent.ToElement ("dummy.packageid").ToString ();

var expected =
@"<intent-filter>
<action p2:name=""pluralAction"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
<data p2:pathSuffix=""pluralSuffix1"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
<data p2:pathSuffix=""pluralSuffix2"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
<data p2:pathAdvancedPattern=""pluralPattern1"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
<data p2:pathAdvancedPattern=""pluralPattern2"" xmlns:p2=""http://schemas.android.com/apk/res/android"" />
</intent-filter>";

StringAssertEx.AreMultiLineEqual (expected, xml);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ public static bool ContainsOccurances (this IEnumerable<string> collection, stri
}
return found == count;
}

// Checks if two string are equal after normalizing string line endings
public static void AreMultiLineEqual (string expected, string actual)
{
expected = expected.ReplaceLineEndings ();
actual = actual.ReplaceLineEndings ();

Assert.AreEqual (expected, actual);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputPath>$(MicrosoftAndroidSdkOutDir)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<DefineConstants>$(DefineConstants);TRACE;HAVE_CECIL;MSBUILD;ANDROID_24</DefineConstants>
<DefineConstants>$(DefineConstants);TRACE;HAVE_CECIL;MSBUILD;ANDROID_24;ANDROID_26;ANDROID_31</DefineConstants>
<AndroidGeneratedClassDirectory Condition=" '$(AndroidGeneratedClassDirectory)' == '' ">..\..\src\Mono.Android\obj\$(Configuration)\$(DotNetTargetFramework)\android-$(AndroidLatestStablePlatformId)\mcw</AndroidGeneratedClassDirectory>
<NoWarn>8632</NoWarn>
<SignAssembly>false</SignAssembly>
Expand Down

0 comments on commit 5a1b9b1

Please sign in to comment.