diff --git a/.gitmodules b/.gitmodules
index 13463abc5dd..abf69bea617 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,7 @@
+[submodule "external/debugger-libs"]
+ path = external/debugger-libs
+ url = git://github.com/mono/debugger-libs
+ branch = master
[submodule "external/dlfcn-win32"]
path = external/dlfcn-win32
url = https://github.com/dlfcn-win32/dlfcn-win32.git
@@ -30,6 +34,10 @@
path = external/mxe
url = https://github.com/xamarin/mxe.git
branch = xamarin
+[submodule "external/nrefactory"]
+ path = external/nrefactory
+ url = git://github.com/icsharpcode/NRefactory.git
+ branch = master
[submodule "external/opentk"]
path = external/opentk
url = https://github.com/mono/opentk.git
diff --git a/Configuration.props b/Configuration.props
index a92d4f50b82..012ce11ef50 100644
--- a/Configuration.props
+++ b/Configuration.props
@@ -176,5 +176,11 @@
$(ManagedRuntime) $(ManagedRuntimeArgs) "$(MSBuildThisFileDirectory)bin\Build$(Configuration)\remap-assembly-ref.exe"
+
+
+ <_Runtime Condition=" '$(HostOS)' != 'Windows' ">$(ManagedRuntime) $(ManagedRuntimeArgs)
+ <_NUnit>$(_Runtime) packages\NUnit.ConsoleRunner.3.9.0\tools\nunit3-console.exe
+
+
diff --git a/Xamarin.Android.Build.Tasks.sln b/Xamarin.Android.Build.Tasks.sln
index e778058faa7..bb2e95c7ab5 100644
--- a/Xamarin.Android.Build.Tasks.sln
+++ b/Xamarin.Android.Build.Tasks.sln
@@ -11,6 +11,20 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Xamarin.Android.Build.Tests
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.ProjectTools", "src\Xamarin.Android.Build.Tasks\Tests\Xamarin.ProjectTools\Xamarin.ProjectTools.csproj", "{2DD1EE75-6D8D-4653-A800-0A24367F7F38}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "external", "external", "{385E71CC-BAE5-488B-805E-ACAE55F01DF5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuildDeviceIntegration", "tests\MSBuildDeviceIntegration\MSBuildDeviceIntegration.csproj", "{16DB2680-399B-4111-AA26-6CDBBFA334D8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "external\nrefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSharp", "external\nrefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj", "{53DCA265-3C3C-42F9-B647-F72BA678122B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugging", "external\debugger-libs\Mono.Debugging\Mono.Debugging.csproj", "{90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugger.Soft", "external\debugger-libs\Mono.Debugger.Soft\Mono.Debugger.Soft.csproj", "{372E8E3E-29D5-4B4D-88A2-4711CD628C4E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugging.Soft", "external\debugger-libs\Mono.Debugging.Soft\Mono.Debugging.Soft.csproj", "{DE40756E-57F6-4AF2-B155-55E3A88CCED8}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems*{3f1f2f50-af1a-4a5a-bedb-193372f068d7}*SharedItemsImports = 4
@@ -34,6 +48,30 @@ Global
{2DD1EE75-6D8D-4653-A800-0A24367F7F38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DD1EE75-6D8D-4653-A800-0A24367F7F38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DD1EE75-6D8D-4653-A800-0A24367F7F38}.Release|Any CPU.Build.0 = Release|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -41,4 +79,11 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F32556C5-6FD4-4F1D-884A-DEDF2EE865F6}
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
+ {53DCA265-3C3C-42F9-B647-F72BA678122B} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
+ EndGlobalSection
EndGlobal
diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln
index 3389d812e39..6ad4ebd033a 100644
--- a/Xamarin.Android.sln
+++ b/Xamarin.Android.sln
@@ -133,6 +133,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "create-pkg", "build-tools\c
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vswhere", "tools\vswhere\vswhere.csproj", "{DBDC804F-8406-4F5E-83C6-720CB0CB6C6F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuildDeviceIntegration", "tests\MSBuildDeviceIntegration\MSBuildDeviceIntegration.csproj", "{16DB2680-399B-4111-AA26-6CDBBFA334D8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "external", "external", "{05C3B1D6-A4CE-4534-A9E4-E9117591ADF7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "external\nrefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSharp", "external\nrefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj", "{53DCA265-3C3C-42F9-B647-F72BA678122B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugger.Soft", "external\debugger-libs\Mono.Debugger.Soft\Mono.Debugger.Soft.csproj", "{372E8E3E-29D5-4B4D-88A2-4711CD628C4E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugging", "external\debugger-libs\Mono.Debugging\Mono.Debugging.csproj", "{90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugging.Soft", "external\debugger-libs\Mono.Debugging.Soft\Mono.Debugging.Soft.csproj", "{DE40756E-57F6-4AF2-B155-55E3A88CCED8}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems*{3f1f2f50-af1a-4a5a-bedb-193372f068d7}*SharedItemsImports = 4
@@ -383,6 +397,30 @@ Global
{DBDC804F-8406-4F5E-83C6-720CB0CB6C6F}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{DBDC804F-8406-4F5E-83C6-720CB0CB6C6F}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{DBDC804F-8406-4F5E-83C6-720CB0CB6C6F}.Release|AnyCPU.Build.0 = Release|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Debug|AnyCPU.Build.0 = Debug|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Release|AnyCPU.ActiveCfg = Release|Any CPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}.Release|AnyCPU.Build.0 = Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|AnyCPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|AnyCPU.ActiveCfg = Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|AnyCPU.Build.0 = Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|AnyCPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|AnyCPU.ActiveCfg = Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|AnyCPU.Build.0 = Release|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Debug|AnyCPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Release|AnyCPU.ActiveCfg = Release|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Release|AnyCPU.Build.0 = Release|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Debug|AnyCPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Release|AnyCPU.ActiveCfg = Release|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Release|AnyCPU.Build.0 = Release|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Debug|AnyCPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Release|AnyCPU.ActiveCfg = Release|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Release|AnyCPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -446,6 +484,12 @@ Global
{0C31DE30-F9DF-4312-BFFE-DCAD558CCF08} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{A0AEF446-3368-4591-9DE6-BC3B2B33337D} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{DBDC804F-8406-4F5E-83C6-720CB0CB6C6F} = {864062D3-A415-4A6F-9324-5820237BA058}
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} = {05C3B1D6-A4CE-4534-A9E4-E9117591ADF7}
+ {53DCA265-3C3C-42F9-B647-F72BA678122B} = {05C3B1D6-A4CE-4534-A9E4-E9117591ADF7}
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E} = {05C3B1D6-A4CE-4534-A9E4-E9117591ADF7}
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2} = {05C3B1D6-A4CE-4534-A9E4-E9117591ADF7}
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8} = {05C3B1D6-A4CE-4534-A9E4-E9117591ADF7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6}
diff --git a/build-tools/scripts/RunTests.targets b/build-tools/scripts/RunTests.targets
index 66c352041c3..2fa51ee5c48 100644
--- a/build-tools/scripts/RunTests.targets
+++ b/build-tools/scripts/RunTests.targets
@@ -8,8 +8,6 @@
- <_Runtime Condition=" '$(HostOS)' != 'Windows' ">$(ManagedRuntime) $(ManagedRuntimeArgs)
- <_NUnit>$(_Runtime) packages\NUnit.ConsoleRunner.3.9.0\tools\nunit3-console.exe
<_Test Condition=" '$(TEST)' != '' ">--test="$(TEST)"
<_XABuild>$(_TopDir)\bin\$(Configuration)\bin\xabuild
<_XABinLogPrefix>/v:normal /binaryLogger:"$(MSBuildThisFileDirectory)\..\..\bin\Test$(Configuration)\msbuild
diff --git a/external/debugger-libs b/external/debugger-libs
new file mode 160000
index 00000000000..b45303f650e
--- /dev/null
+++ b/external/debugger-libs
@@ -0,0 +1 @@
+Subproject commit b45303f650e827b9364fbcc95a7bcb5e2e99f3cc
diff --git a/external/nrefactory b/external/nrefactory
new file mode 160000
index 00000000000..0607a4ad96e
--- /dev/null
+++ b/external/nrefactory
@@ -0,0 +1 @@
+Subproject commit 0607a4ad96ebdd16817e47dcae85b1cfcb5b5bf5
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs
index 577f1430fcc..c685b4f2a6b 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs
@@ -545,9 +545,6 @@ protected override void OnCreate (Bundle bundle)
string.Format ("Unexpected Files found! {0}",
string.Join (Environment.NewLine, additionalFiles.Select (x => x.FullName))));
}
- if (!HasDevices)
- Assert.Ignore ("Skipping Installation. No devices available.");
- Assert.IsTrue (ab.RunTarget (app, "Install"), "App should have installed.");
}
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs
index 1c5f4d5e116..30130fe589c 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs
@@ -8,7 +8,11 @@
using System.Linq;
using System.Security.Cryptography;
using System.Text;
+using System.Text.RegularExpressions;
using System.Threading;
+using System.Xml;
+using System.Xml.Linq;
+using System.Xml.XPath;
using Xamarin.ProjectTools;
using XABuildPaths = Xamarin.Android.Build.Paths;
@@ -154,13 +158,13 @@ public static string AndroidNdkPath {
}
}
- protected void WaitFor(int milliseconds)
+ protected static void WaitFor(int milliseconds)
{
var pause = new ManualResetEvent(false);
pause.WaitOne(milliseconds);
}
- protected static string RunAdbCommand (string command, bool ignoreErrors = true)
+ protected static string RunAdbCommand (string command, bool ignoreErrors = true, int timeout = 30)
{
string ext = Environment.OSVersion.Platform != PlatformID.Unix ? ".exe" : "";
string adb = Path.Combine (AndroidSdkPath, "platform-tools", "adb" + ext);
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs
new file mode 100644
index 00000000000..96ef7ad5d50
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs
@@ -0,0 +1,146 @@
+using NUnit.Framework;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Xml;
+using System.Xml.Linq;
+using System.Xml.XPath;
+using Xamarin.ProjectTools;
+using XABuildPaths = Xamarin.Android.Build.Paths;
+
+namespace Xamarin.Android.Build.Tests
+{
+ public class DeviceTest: BaseTest
+ {
+ protected static void RunAdbInput (string command, params object [] args)
+ {
+ RunAdbCommand ($"shell {command} {string.Join (" ", args)}");
+ }
+
+ protected static string ClearAdbLogcat ()
+ {
+ return RunAdbCommand ("logcat -c");
+ }
+
+ protected static string ClearDebugProperty ()
+ {
+ return RunAdbCommand ("shell setprop debug.mono.extra \"\"");
+ }
+
+ protected static void AdbStartActivity (string activity)
+ {
+ RunAdbCommand ($"shell am start -S -n \"{activity}\"");
+ }
+
+ protected void WaitFor (TimeSpan timeSpan, Func func)
+ {
+ var pause = new ManualResetEvent (false);
+ TimeSpan total = timeSpan;
+ TimeSpan interval = TimeSpan.FromMilliseconds (10);
+ while (total.TotalMilliseconds > 0) {
+ pause.WaitOne (interval);
+ total = total.Subtract (interval);
+ if (func ()) {
+ break;
+ }
+ }
+ }
+
+ protected static bool MonitorAdbLogcat (Func action, int timeout = 10)
+ {
+ string ext = Environment.OSVersion.Platform != PlatformID.Unix ? ".exe" : "";
+ string adb = Path.Combine (AndroidSdkPath, "platform-tools", "adb" + ext);
+ var info = new ProcessStartInfo (adb, "logcat") {
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ };
+ using (var proc = Process.Start (info)) {
+ var sw = new Stopwatch ();
+ try {
+ TimeSpan time = TimeSpan.FromSeconds (timeout);
+ while (time.TotalMilliseconds > 0) {
+ sw.Start ();
+ if (action (proc.StandardOutput.ReadLine ()))
+ return true;
+ time = time.Subtract (TimeSpan.FromMilliseconds (sw.ElapsedMilliseconds));
+ sw.Reset ();
+ }
+ } finally {
+ sw.Stop ();
+ proc.Kill ();
+ proc.WaitForExit ();
+ }
+ return false;
+ }
+ }
+
+ protected static bool WaitForDebuggerToStart (out string output, int timeout = 60)
+ {
+ var sb = new StringBuilder ();
+ bool result = MonitorAdbLogcat ((line) => {
+ sb.AppendLine (line);
+ return line.IndexOf ("monodroid-debug: Trying to initialize the debugger with options", StringComparison.OrdinalIgnoreCase) > 0;
+ }, timeout: timeout);
+ output = sb.ToString ();
+ return result;
+ }
+
+ protected static bool WaitForActivityToStart (string activityNamespace, string activityName, out string output, int timeout = 60)
+ {
+ var sb = new StringBuilder ();
+ bool result = MonitorAdbLogcat ((line) => {
+ sb.AppendLine (line);
+ return line.IndexOf ("ActivityManager: Displayed", StringComparison.OrdinalIgnoreCase) > 0 && line.Contains (activityNamespace) && line.Contains (activityName);
+ }, timeout: timeout);
+ output = sb.ToString ();
+ return result;
+ }
+
+ protected static (int x, int y, int w, int h) GetControlBounds (string packageName, string uiElement, string text)
+ {
+ var regex = new Regex (@"[(0-9)]\d*", RegexOptions.Compiled);
+ var result = (x: 0, y: 0, w: 0, h: 0);
+ var ui = RunAdbCommand ("exec-out uiautomator dump /dev/tty");
+ while (ui.Contains ("ERROR:")) {
+ ui = RunAdbCommand ("exec-out uiautomator dump /dev/tty");
+ WaitFor (1);
+ }
+ ui = ui.Replace ("UI hierchary dumped to: /dev/tty", string.Empty).Trim ();
+ try {
+ var uiDoc = XDocument.Parse (ui);
+ var node = uiDoc.XPathSelectElement ($"//node[contains(@resource-id,'{uiElement}')]");
+ if (node == null)
+ node = uiDoc.XPathSelectElement ($"//node[contains(@content-desc,'{uiElement}')]");
+ if (node == null)
+ node = uiDoc.XPathSelectElement ($"//node[contains(@text,'{text}')]");
+ if (node == null)
+ return result;
+ var bounds = node.Attribute ("bounds");
+ var matches = regex.Matches (bounds.Value);
+ int.TryParse (matches [0].Value, out int x);
+ int.TryParse (matches [1].Value, out int y);
+ int.TryParse (matches [2].Value, out int w);
+ int.TryParse (matches [3].Value, out int h);
+ return (x: x, y: y, w: w, h: h);
+ } catch (Exception ex) {
+ // Ignore any error and return and empty
+ throw new InvalidOperationException ($"uiautomator returned invalid xml {ui}", ex);
+ }
+ }
+
+ protected static void ClickButton (string packageName, string buttonName, string buttonText)
+ {
+ var bounds = GetControlBounds (packageName, buttonName, buttonText);
+ RunAdbInput ("input tap", bounds.x + ((bounds.w - bounds.x) / 2), bounds.y + ((bounds.h - bounds.y) / 2));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.Shared.projitems b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.Shared.projitems
index 948b6bef0d8..735508b6090 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.Shared.projitems
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.Shared.projitems
@@ -19,6 +19,7 @@
+
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj
index e71eb1f8c31..ca5f90ea85d 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj
@@ -58,6 +58,8 @@
..\..\..\..\packages\Xamarin.Build.AsyncTask.0.3.4\lib\netstandard2.0\Xamarin.Build.AsyncTask.dll
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs
index b2ae958df8b..8be46e30b26 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs
@@ -82,6 +82,16 @@ public bool Build (XamarinProject project, bool doNotCleanupOnUpdate = false, st
return result;
}
+ public bool Install (XamarinProject project, bool doNotCleanupOnUpdate = false)
+ {
+ return RunTarget (project, "Install", doNotCleanupOnUpdate);
+ }
+
+ public bool Uninstall (XamarinProject project, bool doNotCleanupOnUpdate = false)
+ {
+ return RunTarget (project, "Uninstall", doNotCleanupOnUpdate);
+ }
+
public bool Restore (XamarinProject project, bool doNotCleanupOnUpdate = false)
{
return RunTarget (project, "Restore", doNotCleanupOnUpdate);
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml
index eedb53ff2bc..2a75ede1a6c 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml
@@ -1,4 +1,4 @@
-
+
@@ -6,5 +6,6 @@
+
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml.cs
index 210e8a95f19..76559763ed0 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Forms/MainPage.xaml.cs
@@ -13,5 +13,10 @@ public MainPage ()
{
InitializeComponent ();
}
+
+ public void Button_Clicked (object sender, EventArgs e)
+ {
+ Console.WriteLine ("Button was Clicked!");
+ }
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
index 5df89aad721..9ff15fd98ac 100755
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
@@ -3389,6 +3389,10 @@ because xbuild doesn't support framework reference assemblies.
_DeployApk;
_DeployAppBundle;
+
+ AndroidPrepareForBuild;
+ _Uninstall
+
+
+
+
+
+
+
+
diff --git a/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj
new file mode 100644
index 00000000000..5721720803d
--- /dev/null
+++ b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj
@@ -0,0 +1,84 @@
+
+
+
+ Debug
+ AnyCPU
+ {16DB2680-399B-4111-AA26-6CDBBFA334D8}
+ Library
+ Xamarin.Android.Build.Tests
+ MSBuildDeviceIntegration
+
+
+
+
+ true
+ false
+ ..\..\bin\TestDebug\MSBuildDeviceIntegration
+ DEBUG;
+ prompt
+ 4
+
+
+ true
+ ..\..\bin\TestRelease\MSBuildDeviceIntegration
+ prompt
+ 4
+
+
+
+
+
+
+ ..\..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll
+
+
+ ..\..\packages\NodaTime.2.4.5\lib\net45\NodaTime.dll
+
+
+
+
+ XABuildPaths.cs
+
+
+ Utilities\DeviceTest.cs
+
+
+ Utilities\BuildHelper.cs
+
+
+ Utilities\BaseTest.cs
+
+
+
+
+
+
+
+
+
+ {2DD1EE75-6D8D-4653-A800-0A24367F7F38}
+ Xamarin.ProjectTools
+
+
+ {E248B2CA-303B-4645-ADDC-9D4459D550FD}
+ libZipSharp
+
+
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}
+ Mono.Debugging.Soft
+
+
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}
+ Mono.Debugger.Soft
+
+
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}
+ Mono.Debugging
+
+
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}
+ ICSharpCode.NRefactory
+
+
+
+
diff --git a/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.targets b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.targets
new file mode 100644
index 00000000000..55ca61176a5
--- /dev/null
+++ b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.targets
@@ -0,0 +1,24 @@
+
+
+
+
+ <_Source Include="..\..\bin\Test$(Configuration)\MSBuildDeviceIntegration\Mono.Debugging.Soft.dll">
+ Mono.Cecil.Mdb
+ ..\..\bin\Test$(Configuration)\MSBuildDeviceIntegration\Xamarin.Android.Cecil.Mdb.dll
+
+ <_Source Include="..\..\bin\Test$(Configuration)\MSBuildDeviceIntegration\Mono.Debugging.Soft.dll">
+ Mono.Cecil
+ ..\..\bin\Test$(Configuration)\MSBuildDeviceIntegration\Xamarin.Android.Cecil.dll
+
+ <_Source Include="..\..\bin\Test$(Configuration)\MSBuildDeviceIntegration\Mono.Debugger.Soft.dll">
+ Mono.Cecil
+ ..\..\bin\Test$(Configuration)\MSBuildDeviceIntegration\Xamarin.Android.Cecil.dll
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs b/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs
new file mode 100644
index 00000000000..2ba1d0c9d1c
--- /dev/null
+++ b/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Net;
+using Mono.Debugging.Client;
+using Mono.Debugging.Soft;
+using NUnit.Framework;
+using Xamarin.ProjectTools;
+
+namespace Xamarin.Android.Build.Tests
+{
+ public class DebuggingTest : DeviceTest {
+ [TearDown]
+ public void ClearDebugProperties ()
+ {
+ ClearDebugProperty ();
+ }
+
+ [Test]
+ [Retry (1)]
+ public void ApplicationRunsWithoutDebugger ([Values (false, true)] bool isRelease)
+ {
+ if (!HasDevices) {
+ Assert.Ignore ("Test needs a device attached.");
+ return;
+ }
+
+ var proj = new XamarinFormsAndroidApplicationProject () {
+ IsRelease = isRelease,
+ };
+ if (isRelease || !CommercialBuildAvailable) {
+ var abis = new string [] { "armeabi-v7a", "x86" };
+ proj.SetProperty (KnownProperties.AndroidSupportedAbis, string.Join (";", abis));
+ }
+ proj.SetDefaultTargetDevice ();
+ using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
+ string apiLevel;
+ proj.TargetFrameworkVersion = b.LatestTargetFrameworkVersion (out apiLevel);
+ proj.AndroidManifest = $@"
+
+
+
+
+";
+ b.Save (proj, saveProject: true);
+ proj.NuGetRestore (Path.Combine (Root, b.ProjectDirectory), b.PackagesDirectory);
+ Assert.True (b.Build (proj), "Project should have built.");
+ Assert.True (b.Install (proj), "Project should have installed.");
+ ClearAdbLogcat ();
+ if (CommercialBuildAvailable)
+ Assert.True (b.RunTarget (proj, "_Run"), "Project should have run.");
+ else
+ AdbStartActivity ($"{proj.PackageName}/md52d9cf6333b8e95e8683a477bc589eda5.MainActivity");
+ Assert.True (WaitForActivityToStart (proj.PackageName, "MainActivity", output: out string output, timeout: 10),
+ "Activity should have started.");
+ Assert.True (b.Uninstall (proj), "Project should have uninstalled.");
+ }
+ }
+
+#pragma warning disable 414
+ static object [] DebuggerTestCases = new object [] {
+ new object[] {
+ /* useSharedRuntime */ false,
+ /* embedAssemblies */ true,
+ /* fastDevType */ "Assemblies",
+ },
+ new object[] {
+ /* useSharedRuntime */ false,
+ /* embedAssemblies */ false,
+ /* fastDevType */ "Assemblies",
+ },
+ new object[] {
+ /* useSharedRuntime */ true,
+ /* embedAssemblies */ true,
+ /* fastDevType */ "Assemblies",
+ },
+ new object[] {
+ /* useSharedRuntime */ true,
+ /* embedAssemblies */ false,
+ /* fastDevType */ "Assemblies",
+ },
+ new object[] {
+ /* useSharedRuntime */ true,
+ /* embedAssemblies */ true,
+ /* fastDevType */ "Assemblies:Dexes",
+ },
+ new object[] {
+ /* useSharedRuntime */ true,
+ /* embedAssemblies */ false,
+ /* fastDevType */ "Assemblies:Dexes",
+ },
+ };
+#pragma warning restore 414
+
+ [Test]
+ [TestCaseSource (nameof(DebuggerTestCases))]
+ [Retry (1)]
+ public void ApplicationRunsWithDebuggerAndBreaks (bool useSharedRuntime, bool embedAssemblies, string fastDevType)
+ {
+ if (!CommercialBuildAvailable) {
+ Assert.Ignore ("Test does not run on the Open Source Builds.");
+ return;
+ }
+ if (!HasDevices) {
+ Assert.Ignore ("Test needs a device attached.");
+ return;
+ }
+ var proj = new XamarinFormsAndroidApplicationProject () {
+ IsRelease = false,
+ AndroidFastDeploymentType = fastDevType
+ };
+ var abis = new string [] { "armeabi-v7a", "x86" };
+ proj.SetProperty (KnownProperties.AndroidSupportedAbis, string.Join (";", abis));
+ proj.SetProperty (KnownProperties.AndroidUseSharedRuntime, useSharedRuntime.ToString ());
+ proj.SetProperty ("EmbedAssembliesIntoApk", embedAssemblies.ToString ());
+ proj.SetDefaultTargetDevice ();
+ using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
+ string apiLevel;
+ proj.TargetFrameworkVersion = b.LatestTargetFrameworkVersion (out apiLevel);
+ proj.AndroidManifest = $@"
+
+
+
+
+";
+ b.Save (proj, saveProject: true);
+ proj.NuGetRestore (Path.Combine (Root, b.ProjectDirectory), b.PackagesDirectory);
+ Assert.True (b.Build (proj), "Project should have built.");
+ Assert.True (b.Install (proj), "Project should have installed.");
+
+ int breakcountHitCount = 0;
+ ManualResetEvent resetEvent = new ManualResetEvent (false);
+ var sw = new Stopwatch ();
+ // setup the debugger
+ var session = new SoftDebuggerSession ();
+ session.Breakpoints = new BreakpointStore {
+ { Path.Combine (Root, b.ProjectDirectory, "MainActivity.cs"), 19 },
+ { Path.Combine (Root, b.ProjectDirectory, "MainPage.xaml.cs"), 14 },
+ { Path.Combine (Root, b.ProjectDirectory, "MainPage.xaml.cs"), 19 },
+ { Path.Combine (Root, b.ProjectDirectory, "App.xaml.cs"), 12 },
+ };
+ session.TargetHitBreakpoint += (sender, e) => {
+ Console.WriteLine ($"BREAK {e.Type}");
+ breakcountHitCount++;
+ session.Continue ();
+ };
+ var rnd = new Random ();
+ int port = rnd.Next (10000, 20000);
+ TestContext.Out.WriteLine ($"{port}");
+ var args = new SoftDebuggerConnectArgs ("", IPAddress.Loopback, port) {
+ MaxConnectionAttempts = 10,
+ };
+ var startInfo = new SoftDebuggerStartInfo (args) {
+ WorkingDirectory = Path.Combine (b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets"),
+ };
+ var options = new DebuggerSessionOptions () {
+ EvaluationOptions = EvaluationOptions.DefaultOptions,
+ };
+ options.EvaluationOptions.UseExternalTypeResolver = true;
+ ClearAdbLogcat ();
+ Assert.True (b.RunTarget (proj, "_Run", parameters: new string [] {
+ $"AndroidSdbTargetPort={port}",
+ $"AndroidSdbHostPort={port}",
+ "AndroidAttachDebugger=True",
+ }), "Project should have run.");
+
+ Assert.IsTrue (WaitForDebuggerToStart (output: out string logcat), "Activity should have started");
+ // we need to give a bit of time for the debug server to start up.
+ WaitFor (2000);
+ session.LogWriter += (isStderr, text) => { Console.WriteLine (text); };
+ session.OutputWriter += (isStderr, text) => { Console.WriteLine (text); };
+ session.DebugWriter += (level, category, message) => { Console.WriteLine (message); };
+ session.Run (startInfo, options);
+ WaitFor (TimeSpan.FromSeconds (30), () => session.IsConnected);
+ Assert.True (session.IsConnected, "Debugger should have connected but it did not.");
+ // we need to wait here for a while to allow the breakpoints to hit
+ // but we need to timeout
+ TimeSpan timeout = TimeSpan.FromSeconds (60);
+ while (session.IsConnected && breakcountHitCount < 3) {
+ Thread.Sleep (10);
+ timeout = timeout.Subtract (TimeSpan.FromMilliseconds (10));
+ }
+ WaitFor (2000);
+ ClearAdbLogcat ();
+ ClickButton (proj.PackageName, "myXFButton", "CLICK ME");
+ while (session.IsConnected && breakcountHitCount < 4) {
+ Thread.Sleep (10);
+ timeout = timeout.Subtract (TimeSpan.FromMilliseconds (10));
+ }
+ int expected = 4;
+ Assert.AreEqual (expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}");
+ Assert.True (b.Uninstall (proj), "Project should have uninstalled.");
+ session.Exit ();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/MSBuildDeviceIntegration/Tests/DeploymentTest.cs b/tests/MSBuildDeviceIntegration/Tests/DeploymentTest.cs
new file mode 100644
index 00000000000..102bc32960b
--- /dev/null
+++ b/tests/MSBuildDeviceIntegration/Tests/DeploymentTest.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using Microsoft.Build.Framework;
+using NUnit.Framework;
+using NUnit.Framework.Interfaces;
+using Xamarin.ProjectTools;
+[assembly: NonParallelizable]
+
+namespace Xamarin.Android.Build.Tests
+{
+ [SingleThreaded]
+ public class DeploymentTest : DeviceTest {
+
+ static ProjectBuilder builder;
+ static XamarinFormsAndroidApplicationProject proj;
+
+ [OneTimeSetUp]
+ public void BeforeDeploymentTests ()
+ {
+ proj = new XamarinFormsAndroidApplicationProject ();
+ proj.SetProperty (KnownProperties.AndroidSupportedAbis, "armeabi-v7a;x86");
+ var mainPage = proj.Sources.First (x => x.Include () == "MainPage.xaml.cs");
+ var source = mainPage.TextContent ().Replace ("InitializeComponent ();", @"InitializeComponent ();
+ Console.WriteLine ($""TimeZoneInfo={TimeZoneInfo.Local.DisplayName}"");
+");
+ mainPage.TextContent = () => source;
+ builder = CreateApkBuilder (Path.Combine ("temp", "DeploymentTests"));
+ string apiLevel;
+ proj.TargetFrameworkVersion = builder.LatestTargetFrameworkVersion (out apiLevel);
+ proj.AndroidManifest = $@"
+
+
+
+
+ ";
+ Assert.IsTrue (builder.Build (proj), "Build should have succeeded.");
+ Assert.IsTrue (builder.Install (proj), "Install should have succeeded.");
+ }
+
+ [OneTimeTearDown]
+ public void AfterDeploymentTests ()
+ {
+ RunAdbCommand ($"uninstall {proj.PackageName}");
+ if (TestContext.CurrentContext.Result.FailCount == 0 && Directory.Exists (builder.ProjectDirectory))
+ Directory.Delete (builder.ProjectDirectory, recursive: true);
+ }
+
+
+ [Test]
+ public void CheckXamarinFormsAppDeploysAndAButtonWorks ()
+ {
+ if (!HasDevices)
+ Assert.Ignore ("Skipping Test. No devices available.");
+ AdbStartActivity ($"{proj.PackageName}/md52d9cf6333b8e95e8683a477bc589eda5.MainActivity");
+ WaitForActivityToStart (proj.PackageName, "MainActivity", output: out string output, timeout: 10);
+ ClearAdbLogcat ();
+ ClickButton (proj.PackageName, "myXFButton", "CLICK ME");
+ Assert.IsTrue (MonitorAdbLogcat ((line) => {
+ return line.Contains ("Button was Clicked!");
+ }),"Button Should have been Clicked.");
+ }
+
+ static object [] GetTimeZoneTestCases ()
+ {
+ List