Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] fix for utf8 chars and custom views (#4726
Browse files Browse the repository at this point in the history
)

Fixes: https://feedback.devdiv.io/955972

Context: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1084873
Context: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1130421

Android layout files with UTF-8 characters and custom views fail to
build with:

	error APT2258: not well-formed (invalid token).

In be47b3e, I inadvertently changed the `<ConvertCustomView/>`
MSBuild task to save changes using [`Encoding.Default`][0], which
defaults to the "ANSI" codepage on Windows, and thus cannot store
the entirety of Unicode characters.

`XDocumentExtensions.SaveIfChanged()` should instead use
`MonoAndroidHelper.UTF8withoutBOM` by default.

I updated two tests to reproduce this issue.

Review other uses of `MemoryStreamPool.Shared.CreateStreamWriter()`
and `Encoding.Default` in general to ensure that we're not using
`Encoding.Default` where we shouldn't be.

[0]: https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding.default?view=netcore-3.1
  • Loading branch information
jonathanpeppers authored May 27, 2020
1 parent d298fda commit 72bb668
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ void Run (DirectoryAssemblyResolver res)
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)) {
using (var acw_map = MemoryStreamPool.Shared.CreateStreamWriter ()) {
foreach (TypeDefinition type in javaTypes) {
string managedKey = type.FullName.Replace ('/', '.');
string javaKey = JavaNativeTypeManager.ToJniName (type).Replace ('/', '.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2586,11 +2586,17 @@ public void BuildReleaseApplication ()
[Category ("SmokeTests")]
public void BuildApplicationWithSpacesInPath ([Values (true, false)] bool enableMultiDex, [Values ("dx", "d8")] string dexTool, [Values ("", "proguard", "r8")] string linkTool)
{
var folderName = $"BuildReleaseApp AndÜmläüts({enableMultiDex}{dexTool}{linkTool})";
var lib = new XamarinAndroidLibraryProject {
IsRelease = true,
ProjectName = "Library1"
};
var proj = new XamarinAndroidApplicationProject () {
IsRelease = true,
AotAssemblies = true,
DexTool = dexTool,
LinkTool = linkTool,
References = { new BuildItem ("ProjectReference", $"..\\{folderName}Library1\\Library1.csproj") }
};
proj.OtherBuildItems.Add (new BuildItem ("AndroidJavaLibrary", "Hello (World).jar") { BinaryContent = () => Convert.FromBase64String (@"
UEsDBBQACAgIAMl8lUsAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMAUEsHCAAAAAACAAAAA
Expand Down Expand Up @@ -2620,7 +2626,9 @@ public void BuildApplicationWithSpacesInPath ([Values (true, false)] bool enable
</Project>
",
});
using (var b = CreateApkBuilder (Path.Combine ("temp", $"BuildReleaseAppWithA InItAndÜmläüts({enableMultiDex}{dexTool}{linkTool})"))) {
using (var libb = CreateDllBuilder (Path.Combine ("temp", $"{folderName}Library1")))
using (var b = CreateApkBuilder (Path.Combine ("temp", folderName))) {
libb.Build (lib);
if (dexTool == "d8" && linkTool == "proguard") {
b.ThrowOnBuildFailure = false;
Assert.IsFalse (b.Build (proj), "Build should have failed.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ public CustomTextView(Context context, IAttributeSet attributes) : base(context,
}
};
// Use a custom view
app.LayoutMain = app.LayoutMain.Replace ("</LinearLayout>", "<MyApp.CustomTextView android:id=\"@+id/myText\" /></LinearLayout>");
app.LayoutMain = app.LayoutMain.Replace ("</LinearLayout>", "<MyApp.CustomTextView android:id=\"@+id/myText\" android:text=\"à请\" /></LinearLayout>");
app.SetProperty ("AndroidUseAapt2", useAapt2.ToString ());

int count = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ public static Dictionary<string, HashSet<string>> LoadCustomViewMapFile (IBuildE
public static bool SaveCustomViewMapFile (IBuildEngine4 engine, string mapFile, Dictionary<string, HashSet<string>> map)
{
engine?.RegisterTaskObject (mapFile, map, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false);
using (var writer = MemoryStreamPool.Shared.CreateStreamWriter (Encoding.Default)) {
using (var writer = MemoryStreamPool.Shared.CreateStreamWriter ()) {
foreach (var i in map.OrderBy (x => x.Key)) {
foreach (var v in i.Value.OrderBy (x => x))
writer.WriteLine ($"{i.Key};{v}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static string ToFullString (this XElement element)

public static bool SaveIfChanged (this XDocument document, string fileName)
{
using (var sw = MemoryStreamPool.Shared.CreateStreamWriter (Encoding.Default))
using (var sw = MemoryStreamPool.Shared.CreateStreamWriter ())
using (var xw = new Monodroid.LinePreservedXmlWriter (sw)) {
xw.WriteNode (document.CreateNavigator (), false);
xw.Flush ();
Expand Down

0 comments on commit 72bb668

Please sign in to comment.