diff --git a/build-tools/xaprepare/xaprepare/Application/Utilities.cs b/build-tools/xaprepare/xaprepare/Application/Utilities.cs
index eb2a9393525..e594209db44 100644
--- a/build-tools/xaprepare/xaprepare/Application/Utilities.cs
+++ b/build-tools/xaprepare/xaprepare/Application/Utilities.cs
@@ -867,154 +867,7 @@ void LogError (string message)
public static string GetRelativePath (string relativeTo, string path)
{
- return GetRelativePath (relativeTo, path, Context.Instance.OS.DefaultStringComparison);
+ return Xamarin.Android.Tools.PathUtil.GetRelativePath (relativeTo, path, Context.Instance.OS.DefaultStringComparison);
}
-
- // Adapted from CoreFX sources
- public static string GetRelativePath (string relativeTo, string path, StringComparison comparisonType)
- {
- if (String.IsNullOrEmpty (relativeTo))
- throw new ArgumentException ("must not be null or empty", nameof (relativeTo));
-
- if (String.IsNullOrEmpty (path))
- throw new ArgumentException ("must not be null or empty", nameof (path));
-
- relativeTo = Path.GetFullPath (relativeTo);
- path = Path.GetFullPath (path);
-
- // Need to check if the roots are different- if they are we need to return the "to" path.
- if (!AreRootsEqual (relativeTo, path, comparisonType))
- return path;
-
- int commonLength = GetCommonPathLength (relativeTo, path, ignoreCase: comparisonType == StringComparison.OrdinalIgnoreCase);
-
- // If there is nothing in common they can't share the same root, return the "to" path as is.
- if (commonLength == 0)
- return path;
-
- // Trailing separators aren't significant for comparison
- int relativeToLength = relativeTo.Length;
- if (EndsInDirectorySeparator (relativeTo))
- relativeToLength--;
-
- bool pathEndsInSeparator = EndsInDirectorySeparator (path);
- int pathLength = path.Length;
- if (pathEndsInSeparator)
- pathLength--;
-
- // If we have effectively the same path, return "."
- if (relativeToLength == pathLength && commonLength >= relativeToLength)
- return ".";
-
- // We have the same root, we need to calculate the difference now using the
- // common Length and Segment count past the length.
- //
- // Some examples:
- //
- // C:\Foo C:\Bar L3, S1 -> ..\Bar
- // C:\Foo C:\Foo\Bar L6, S0 -> Bar
- // C:\Foo\Bar C:\Bar\Bar L3, S2 -> ..\..\Bar\Bar
- // C:\Foo\Foo C:\Foo\Bar L7, S1 -> ..\Bar
-
- var sb = new StringBuilder (Math.Max (relativeTo.Length, path.Length));
-
- // Add parent segments for segments past the common on the "from" path
- if (commonLength < relativeToLength) {
- sb.Append ("..");
-
- for (int i = commonLength + 1; i < relativeToLength; i++) {
- if (IsDirectorySeparator (relativeTo[i])) {
- sb.Append (Path.DirectorySeparatorChar);
- sb.Append ("..");
- }
- }
- } else if (IsDirectorySeparator (path[commonLength])) {
- // No parent segments and we need to eat the initial separator
- // (C:\Foo C:\Foo\Bar case)
- commonLength++;
- }
-
- // Now add the rest of the "to" path, adding back the trailing separator
- int differenceLength = pathLength - commonLength;
- if (pathEndsInSeparator)
- differenceLength++;
-
- if (differenceLength > 0) {
- if (sb.Length > 0) {
- sb.Append (Path.DirectorySeparatorChar);
- }
-
- sb.Append(path, commonLength, differenceLength);
- }
-
- return sb.ToString ();
- }
-
- // Adapted from CoreFX sources
- static bool AreRootsEqual (string first, string second, StringComparison comparisonType)
- {
- int firstRootLength = GetRootLength (first);
- int secondRootLength = GetRootLength (second);
-
- return firstRootLength == secondRootLength
- && String.Compare (
- strA: first,
- indexA: 0,
- strB: second,
- indexB: 0,
- length: firstRootLength,
- comparisonType: comparisonType) == 0;
- }
-
- // Adapted from CoreFX sources
- static int GetCommonPathLength (string first, string second, bool ignoreCase)
- {
- int commonChars = EqualStartingCharacterCount (first, second, ignoreCase: ignoreCase);
-
- // If nothing matches
- if (commonChars == 0)
- return commonChars;
-
- // Or we're a full string and equal length or match to a separator
- if (commonChars == first.Length && (commonChars == second.Length || IsDirectorySeparator (second[commonChars])))
- return commonChars;
-
- if (commonChars == second.Length && IsDirectorySeparator (first[commonChars]))
- return commonChars;
-
- // It's possible we matched somewhere in the middle of a segment e.g. C:\Foodie and C:\Foobar.
- while (commonChars > 0 && !IsDirectorySeparator (first[commonChars - 1]))
- commonChars--;
-
- return commonChars;
- }
-
- // Adapted from CoreFX sources
- static unsafe int EqualStartingCharacterCount (string first, string second, bool ignoreCase)
- {
- if (String.IsNullOrEmpty (first) || string.IsNullOrEmpty (second))
- return 0;
-
- int commonChars = 0;
- fixed (char* f = first) {
- fixed (char* s = second) {
- char* l = f;
- char* r = s;
- char* leftEnd = l + first.Length;
- char* rightEnd = r + second.Length;
-
- while (l != leftEnd && r != rightEnd && (*l == *r || (ignoreCase && char.ToUpperInvariant ((*l)) == char.ToUpperInvariant ((*r))))) {
- commonChars++;
- l++;
- r++;
- }
- }
- }
-
- return commonChars;
- }
-
- // Adapted from CoreFX sources
- static bool EndsInDirectorySeparator (string path) => path.Length > 0 && IsDirectorySeparator (path[path.Length - 1]);
}
}
diff --git a/build-tools/xaprepare/xaprepare/xaprepare.csproj b/build-tools/xaprepare/xaprepare/xaprepare.csproj
index 2d5dc260e70..6730c7adae9 100644
--- a/build-tools/xaprepare/xaprepare/xaprepare.csproj
+++ b/build-tools/xaprepare/xaprepare/xaprepare.csproj
@@ -44,6 +44,10 @@
+
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets
index fd0674e9946..7b6191bf61e 100644
--- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets
+++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets
@@ -41,6 +41,19 @@ It is shared between "legacy" binding projects and .NET 5 projects.
+
+
+ <_GeneratedManagedBindingFiles Include="$(GeneratedOutputPath)**\*.cs" />
+
+
+
+
+
+
+
@@ -107,14 +120,23 @@ It is shared between "legacy" binding projects and .NET 5 projects.
+
+
+
+
+
+ Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' Or '@(_GeneratedManagedBindingFiles->Count())' != '0' "
+ DependsOnTargets="GenerateBindings;_CollectGeneratedManagedBindingFiles">
+
+
+ true
+
-
+
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets
index 24d8d93c9c4..346c89aa99b 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets
@@ -118,6 +118,7 @@ properties that determine build ordering.
_BuildResourceDesigner;
UpdateAndroidInterfaceProxies;
_SetAndroidGenerateManagedBindings;
+ _ClearGeneratedManagedBindings;
AddBindingsToCompile;
_CheckForInvalidDesignerConfig;
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs
index fd9c73a4298..b404d91156e 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs
@@ -127,6 +127,8 @@ public State BeginPartialClassFile (StreamWriter writer, string bindingClassName
return state;
}
+ public abstract void SetCodeBehindDir (string path);
+
protected abstract void BeginPartialClassFile (State state, string classNamespace, string className);
public abstract void EndPartialClassFile (State state);
public abstract void WritePartialClassProperty (State state, LayoutWidget widget);
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs
index c5dc083427d..bc2b9ff6db4 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs
@@ -1,6 +1,8 @@
using System;
using System.IO;
using System.Linq;
+using Xamarin.Android.Tasks.LLVMIR;
+using Xamarin.Android.Tools;
namespace Xamarin.Android.Tasks
{
@@ -10,6 +12,7 @@ sealed class CSharpBindingGenerator : BindingGenerator
{
const string BindingPartialClassBackingFieldName = "__layout_binding";
+ string codebehindDir = string.Empty;
protected override string LineCommentString => "//";
protected override string DocCommentString => "///";
public override string LanguageName => "C#";
@@ -28,6 +31,11 @@ protected override void BeginPartialClassFile (State state, string classNamespac
state.WriteLine ();
}
+ public override void SetCodeBehindDir(string path)
+ {
+ codebehindDir = Path.GetFullPath (path);
+ }
+
public override void EndPartialClassFile (State state)
{
EndBindingFile (state); // currently they're identical
@@ -239,7 +247,8 @@ protected override void WriteLocationDirective (State state, LayoutWidget widget
if (loc == null)
return;
- WriteLineIndent (state, $"#line {loc.Line} \"{loc.FilePath}\"");
+ var relativePath = PathUtil.GetRelativePath (codebehindDir, Path.GetFullPath (loc.FilePath));
+ WriteLineIndent (state, $"#line {loc.Line} \"{relativePath}\"");
state.WriteLine ();
}
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs
index 161fc7e374c..1c721326b42 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs
@@ -107,6 +107,8 @@ public async override System.Threading.Tasks.Task RunTaskAsync ()
return;
}
+ generator.SetCodeBehindDir (MonoAndroidCodeBehindDir);
+
LogDebugMessage ($"Generating {generator.LanguageName} binding sources");
var layoutGroups = new Dictionary (StringComparer.Ordinal);
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs
index c653639bfd0..99e9a963422 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs
@@ -1247,9 +1247,9 @@ protected override void OnCreate (Bundle bundle)
proj.SetProperty ("AndroidGenerateLayoutBindings", "True");
using (var builder = CreateApkBuilder (path)) {
Assert.IsTrue (builder.Build (proj), "Build should have succeeded.");
- FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "generated", "Binding.Main.g.cs"));
+ FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "codebehind", "Binding.Main.g.cs"));
Assert.IsTrue (builder.Build (proj), "Second build should have succeeded.");
- FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "generated", "Binding.Main.g.cs"));
+ FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "codebehind", "Binding.Main.g.cs"));
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs
index 70e42e8c71f..7fb2f61bfd7 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs
@@ -534,6 +534,8 @@ public void AppWithSingleJar ()
var builder = CreateApkBuilder ();
Assert.IsTrue (builder.Build (proj), "first build should succeed");
+ Assert.IsTrue (builder.DesignTimeBuild (proj), "Design time build should succeed.");
+ Assert.IsFalse (builder.Output.IsTargetSkipped ("AddBindingsToCompile"), "AddBindingsToCompile should run.");
var assemblyPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll");
var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest";
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs
index a64a11f7bce..6c87875bfa0 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs
@@ -124,7 +124,7 @@ public TestProjectInfo (string projectName, string testName, string rootDirector
ProjectName = projectName;
ObjPath = Path.Combine (rootDirectory, "obj");
- GeneratedPath = Path.Combine (ObjPath, XABuildPaths.Configuration, "generated");
+ GeneratedPath = Path.Combine (ObjPath, XABuildPaths.Configuration, "codebehind");
BinPath = Path.Combine (rootDirectory, "bin", XABuildPaths.Configuration);
ProjectPath = Path.Combine (rootDirectory, $"{projectName}.csproj");
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/PathUtil.cs b/src/Xamarin.Android.Build.Tasks/Utilities/PathUtil.cs
new file mode 100644
index 00000000000..5156ca8aa9a
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/PathUtil.cs
@@ -0,0 +1,289 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace Xamarin.Android.Tools
+{
+ public static class PathUtil
+ {
+
+ const int DevicePrefixLength = 4;
+ const int UncPrefixLength = 2;
+ const int UncExtendedPrefixLength = 8;
+
+ internal const char VolumeSeparatorChar = ':';
+
+ static bool IsWindows = Path.DirectorySeparatorChar == '\\';
+ // Adapted from CoreFX sources
+ public static string GetRelativePath(string relativeTo, string path, StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
+ {
+ if (String.IsNullOrEmpty(relativeTo))
+ throw new ArgumentException("must not be null or empty", nameof(relativeTo));
+
+ if (String.IsNullOrEmpty(path))
+ throw new ArgumentException("must not be null or empty", nameof(path));
+
+ relativeTo = Path.GetFullPath(relativeTo);
+ path = Path.GetFullPath(path);
+
+ // Need to check if the roots are different- if they are we need to return the "to" path.
+ if (!AreRootsEqual(relativeTo, path, comparisonType))
+ return path;
+
+ int commonLength = GetCommonPathLength(relativeTo, path, ignoreCase: comparisonType == StringComparison.OrdinalIgnoreCase);
+
+ // If there is nothing in common they can't share the same root, return the "to" path as is.
+ if (commonLength == 0)
+ return path;
+
+ // Trailing separators aren't significant for comparison
+ int relativeToLength = relativeTo.Length;
+ if (EndsInDirectorySeparator(relativeTo))
+ relativeToLength--;
+
+ bool pathEndsInSeparator = EndsInDirectorySeparator(path);
+ int pathLength = path.Length;
+ if (pathEndsInSeparator)
+ pathLength--;
+
+ // If we have effectively the same path, return "."
+ if (relativeToLength == pathLength && commonLength >= relativeToLength)
+ return ".";
+
+ // We have the same root, we need to calculate the difference now using the
+ // common Length and Segment count past the length.
+ //
+ // Some examples:
+ //
+ // C:\Foo C:\Bar L3, S1 -> ..\Bar
+ // C:\Foo C:\Foo\Bar L6, S0 -> Bar
+ // C:\Foo\Bar C:\Bar\Bar L3, S2 -> ..\..\Bar\Bar
+ // C:\Foo\Foo C:\Foo\Bar L7, S1 -> ..\Bar
+
+ var sb = new StringBuilder(Math.Max(relativeTo.Length, path.Length));
+
+ // Add parent segments for segments past the common on the "from" path
+ if (commonLength < relativeToLength)
+ {
+ sb.Append("..");
+
+ for (int i = commonLength + 1; i < relativeToLength; i++)
+ {
+ if (IsDirectorySeparator(relativeTo[i]))
+ {
+ sb.Append(Path.DirectorySeparatorChar);
+ sb.Append("..");
+ }
+ }
+ }
+ else if (IsDirectorySeparator(path[commonLength]))
+ {
+ // No parent segments and we need to eat the initial separator
+ // (C:\Foo C:\Foo\Bar case)
+ commonLength++;
+ }
+
+ // Now add the rest of the "to" path, adding back the trailing separator
+ int differenceLength = pathLength - commonLength;
+ if (pathEndsInSeparator)
+ differenceLength++;
+
+ if (differenceLength > 0)
+ {
+ if (sb.Length > 0)
+ {
+ sb.Append(Path.DirectorySeparatorChar);
+ }
+
+ sb.Append(path, commonLength, differenceLength);
+ }
+
+ return sb.ToString();
+ }
+
+ // Adapted from CoreFX sources
+ static bool AreRootsEqual(string first, string second, StringComparison comparisonType)
+ {
+ int firstRootLength = GetRootLength(first);
+ int secondRootLength = GetRootLength(second);
+
+ return firstRootLength == secondRootLength
+ && String.Compare(
+ strA: first,
+ indexA: 0,
+ strB: second,
+ indexB: 0,
+ length: firstRootLength,
+ comparisonType: comparisonType) == 0;
+ }
+
+ // Adapted from CoreFX sources
+ static int GetCommonPathLength(string first, string second, bool ignoreCase)
+ {
+ int commonChars = EqualStartingCharacterCount(first, second, ignoreCase: ignoreCase);
+
+ // If nothing matches
+ if (commonChars == 0)
+ return commonChars;
+
+ // Or we're a full string and equal length or match to a separator
+ if (commonChars == first.Length && (commonChars == second.Length || IsDirectorySeparator(second[commonChars])))
+ return commonChars;
+
+ if (commonChars == second.Length && IsDirectorySeparator(first[commonChars]))
+ return commonChars;
+
+ // It's possible we matched somewhere in the middle of a segment e.g. C:\Foodie and C:\Foobar.
+ while (commonChars > 0 && !IsDirectorySeparator(first[commonChars - 1]))
+ commonChars--;
+
+ return commonChars;
+ }
+
+ // Adapted from CoreFX sources
+ static unsafe int EqualStartingCharacterCount(string first, string second, bool ignoreCase)
+ {
+ if (String.IsNullOrEmpty(first) || string.IsNullOrEmpty(second))
+ return 0;
+
+ int commonChars = 0;
+ fixed (char* f = first)
+ {
+ fixed (char* s = second)
+ {
+ char* l = f;
+ char* r = s;
+ char* leftEnd = l + first.Length;
+ char* rightEnd = r + second.Length;
+
+ while (l != leftEnd && r != rightEnd && (*l == *r || (ignoreCase && char.ToUpperInvariant((*l)) == char.ToUpperInvariant((*r)))))
+ {
+ commonChars++;
+ l++;
+ r++;
+ }
+ }
+ }
+
+ return commonChars;
+ }
+
+ // Adapted from CoreFX sources
+ static bool EndsInDirectorySeparator(string path) => path.Length > 0 && IsDirectorySeparator(path[path.Length - 1]);
+
+ static bool IsDirectorySeparator(char c)
+ {
+ if (!IsWindows)
+ return c == Path.DirectorySeparatorChar;
+ return c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar;
+ }
+
+ // Adapted from CoreFX sources
+ static int GetRootLength(string path)
+ {
+ if (!IsWindows)
+ return path.Length > 0 && IsDirectorySeparator(path[0]) ? 1 : 0;
+ return GetRootLength_ForWindows(path);
+ }
+
+ internal static bool IsValidDriveChar(char value)
+ {
+ return ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z'));
+ }
+
+ // Adapted from CoreFX sources
+ static bool IsExtended(string path)
+ {
+ // While paths like "//?/C:/" will work, they're treated the same as "\\.\" paths.
+ // Skipping of normalization will *only* occur if back slashes ('\') are used.
+ return path.Length >= DevicePrefixLength
+ && path[0] == '\\'
+ && (path[1] == '\\' || path[1] == '?')
+ && path[2] == '?'
+ && path[3] == '\\';
+ }
+
+ // Adapted from CoreFX sources
+ static bool IsDevice(string path)
+ {
+ // If the path begins with any two separators is will be recognized and normalized and prepped with
+ // "\??\" for internal usage correctly. "\??\" is recognized and handled, "/??/" is not.
+ return IsExtended(path) ||
+ (
+ path.Length >= DevicePrefixLength
+ && IsDirectorySeparator(path[0])
+ && IsDirectorySeparator(path[1])
+ && (path[2] == '.' || path[2] == '?')
+ && IsDirectorySeparator(path[3])
+ );
+ }
+
+ // Adapted from CoreFX sources
+ static bool IsDeviceUNC(string path)
+ {
+ return path.Length >= UncExtendedPrefixLength
+ && IsDevice(path)
+ && IsDirectorySeparator(path[7])
+ && path[4] == 'U'
+ && path[5] == 'N'
+ && path[6] == 'C';
+ }
+
+ // Adapted from CoreFX sources
+ static int GetRootLength_ForWindows(string path)
+ {
+ int pathLength = path.Length;
+ int i = 0;
+
+ bool deviceSyntax = IsDevice(path);
+ bool deviceUnc = deviceSyntax && IsDeviceUNC(path);
+
+ if ((!deviceSyntax || deviceUnc) && pathLength > 0 && IsDirectorySeparator(path[0]))
+ {
+ // UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo")
+ if (deviceUnc || (pathLength > 1 && IsDirectorySeparator(path[1])))
+ {
+ // UNC (\\?\UNC\ or \\), scan past server\share
+
+ // Start past the prefix ("\\" or "\\?\UNC\")
+ i = deviceUnc ? UncExtendedPrefixLength : UncPrefixLength;
+
+ // Skip two separators at most
+ int n = 2;
+ while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0))
+ i++;
+ }
+ else
+ {
+ // Current drive rooted (e.g. "\foo")
+ i = 1;
+ }
+ }
+ else if (deviceSyntax)
+ {
+ // Device path (e.g. "\\?\.", "\\.\")
+ // Skip any characters following the prefix that aren't a separator
+ i = DevicePrefixLength;
+ while (i < pathLength && !IsDirectorySeparator(path[i]))
+ i++;
+
+ // If there is another separator take it, as long as we have had at least one
+ // non-separator after the prefix (e.g. don't take "\\?\\", but take "\\?\a\")
+ if (i < pathLength && i > DevicePrefixLength && IsDirectorySeparator(path[i]))
+ i++;
+ }
+ else if (pathLength >= 2 && path[1] == VolumeSeparatorChar && IsValidDriveChar(path[0]))
+ {
+ // Valid drive specified path ("C:", "D:", etc.)
+ i = 2;
+
+ // If the colon is followed by a directory separator, move past it (e.g "C:\")
+ if (pathLength > 2 && IsDirectorySeparator(path[2]))
+ i++;
+ }
+
+ return i;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
index 71e64a76db7..b639a9dd4ba 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
@@ -917,7 +917,7 @@ because xbuild doesn't support framework reference assemblies.
Resources
$(IntermediateOutputPath)
- $(IntermediateOutputPath)generated
+ $(IntermediateOutputPath)codebehind
$(IntermediateOutputPath)resourcecache
<_AndroidIntermediateJavaSourceDirectory>$(IntermediateOutputPath)android\src\
<_AndroidIntermediateDexOutputDirectory>$(IntermediateOutputPath)android\bin\
@@ -2550,6 +2550,8 @@ because xbuild doesn't support framework reference assemblies.
+
+