diff --git a/Documentation/DevelopmentTips.md b/Documentation/DevelopmentTips.md
index 4c20dafff0a..05557888972 100644
--- a/Documentation/DevelopmentTips.md
+++ b/Documentation/DevelopmentTips.md
@@ -148,15 +148,15 @@ make variable:
## Running Individual `.apk` Projects
See also the [`tests/RunApkTests.targets`](../tests/RunApkTests.targets) and
-[`build-tools/scripts/UnitTestApks.targets`](../build-tools/scripts/UnitTestApks.targets)
+[`build-tools/scripts/TestApks.targets`](../build-tools/scripts/TestApks.targets)
files.
All `.apk`-based unit test projects provide the following targets:
-* `DeployUnitTestApks`: Installs the associated `.apk` to an Android device.
-* `UndeployUnitTestApks`: Uninstalls the associated `.apk` from an Android device.
-* `RunUnitTestApks`: Executes the unit tests contained within a `.apk`.
- Must be executed *after* the `DeployUnitTestApks` target.
+* `DeployTestApks`: Installs the associated `.apk` to an Android device.
+* `UndeployTestApks`: Uninstalls the associated `.apk` from an Android device.
+* `RunTestApks`: Executes the unit tests contained within a `.apk`.
+ Must be executed *after* the `DeployTestApks` target.
To run an individual `.apk`-based test project, a package must be built, using the
`SignAndroidPackage` target, installed, and executed.
@@ -164,23 +164,23 @@ To run an individual `.apk`-based test project, a package must be built, using t
For example:
$ tools/scripts/xabuild /t:SignAndroidPackage tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
- $ tools/scripts/xabuild /t:DeployUnitTestApks tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
- $ tools/scripts/xabuild /t:RunUnitTestApks tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
+ $ tools/scripts/xabuild /t:DeployTestApks tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
+ $ tools/scripts/xabuild /t:RunTestApks tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
### Running A Single Test Fixture
A single NUnit *Test Fixture* -- a class with the `[TestFixture]`
custom attribute -- may be executed instead of executing *all* test fixtures.
-The `RunUnitTestApks` target accepts a `TestFixture` MSBuild property
+The `RunTestApks` target accepts a `TestFixture` MSBuild property
to specify the test fixture class to execute:
- $ tools/scripts/xabuild /t:RunUnitTestApks \
+ $ tools/scripts/xabuild /t:RunTestApks \
/p:TestFixture=Xamarin.Android.LocaleTests.SatelliteAssemblyTests \
tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
If using `Xamarin.Android.NUnitLite` for projects outside the `xamarin-android`
-repository, such as NUnit tests for a custom app, the `RunUnitTestApks` target
+repository, such as NUnit tests for a custom app, the `RunTestApks` target
will not exist. In such scenarios, the [`adb shell am`][adb-shell-am]
`instrument` command can be used instead. It follows the format:
diff --git a/Xamarin.Android-Tests.sln b/Xamarin.Android-Tests.sln
index 8aa0169dced..0c5521095a8 100644
--- a/Xamarin.Android-Tests.sln
+++ b/Xamarin.Android-Tests.sln
@@ -45,6 +45,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.BindingReso
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.BindingResolveImports-Tests", "tests\ResolveImports\Xamarin.Android.BindingResolveImports-Tests\Xamarin.Android.BindingResolveImports-Tests.csproj", "{B297008B-C313-455E-B230-E119589D2D79}"
EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Xamarin.Forms.Performance.Integration", "tests\Xamarin.Forms-Performance-Integration\Xamarin.Forms.Performance.Integration.shproj", "{195BE9C2-1F91-40DC-BD6D-DE860BF083FB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Performance.Integration.Droid", "tests\Xamarin.Forms-Performance-Integration\Droid\Xamarin.Forms.Performance.Integration.Droid.csproj", "{576312CC-83FF-48B1-A473-488CDC7121AD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -115,6 +119,10 @@ Global
{B297008B-C313-455E-B230-E119589D2D79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B297008B-C313-455E-B230-E119589D2D79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B297008B-C313-455E-B230-E119589D2D79}.Release|Any CPU.Build.0 = Release|Any CPU
+ {576312CC-83FF-48B1-A473-488CDC7121AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {576312CC-83FF-48B1-A473-488CDC7121AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {576312CC-83FF-48B1-A473-488CDC7121AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {576312CC-83FF-48B1-A473-488CDC7121AD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2305B00D-DE81-4744-B0DA-357835CAFE5A} = {43A4FB09-279A-4138-8027-EC1E1CED2E8A}
diff --git a/build-tools/scripts/UnitTestApks.targets b/build-tools/scripts/TestApks.targets
similarity index 83%
rename from build-tools/scripts/UnitTestApks.targets
rename to build-tools/scripts/TestApks.targets
index 0bc00ec9c33..a5ecf7d2d04 100644
--- a/build-tools/scripts/UnitTestApks.targets
+++ b/build-tools/scripts/TestApks.targets
@@ -4,13 +4,14 @@
+
- <_TestImageName>XamarinAndroidUnitTestRunner
+ <_TestImageName>XamarinAndroidTestRunner
<_AdbEmulatorPort>5570
@@ -107,54 +108,62 @@
-
+
-
+
-
+
+
+
<_LogcatFilename>logcat-$(Configuration)$(_AotName).txt
+ ApplicationPackageName="%(TestApk.Package)"
+ ResultsFilename="%(TestApk.ResultsPath)"
+ DefinitionsFilename="%(TestApk.TimingDefinitionsFilename)"
+ AddResults="true"
+ Activity="%(TestApk.Activity)" />
diff --git a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/ProcessLogcatTiming.cs b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/ProcessLogcatTiming.cs
index 195e9238b23..d40e34aa357 100644
--- a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/ProcessLogcatTiming.cs
+++ b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/ProcessLogcatTiming.cs
@@ -10,13 +10,16 @@ namespace Xamarin.Android.BuildTools.PrepTasks
{
public class ProcessLogcatTiming : ProcessPlotInput
{
+ public string Activity { get; set; }
+
public override bool Execute ()
{
LoadDefinitions ();
using (var reader = new StreamReader (InputFilename)) {
string line;
int pid = -1;
- var procStartRegex = new Regex ($@"^(?\d+-\d+\s+[\d:\.]+)\s+.*ActivityManager: Start proc.*for added application {ApplicationPackageName}: pid=(?\d+)");
+ var procIdentification = string.IsNullOrEmpty (Activity) ? $"added application {ApplicationPackageName}" : $"activity {Activity}";
+ var procStartRegex = new Regex ($@"^(?\d+-\d+\s+[\d:\.]+)\s+.*ActivityManager: Start proc.*for {procIdentification}: pid=(?\d+)");
Regex timingRegex = null;
DateTime start = DateTime.Now;
DateTime last = start;
diff --git a/src/Mono.Android/Test/Mono.Android-Tests.projitems b/src/Mono.Android/Test/Mono.Android-Tests.projitems
index 65b62e182ce..13bc4d032f6 100644
--- a/src/Mono.Android/Test/Mono.Android-Tests.projitems
+++ b/src/Mono.Android/Test/Mono.Android-Tests.projitems
@@ -8,14 +8,14 @@
<_MonoAndroidTestApkSizesInput>apk-sizes-$(_MonoAndroidTestPackage)-$(Configuration)$(_AotName).txt
-
+
$(_MonoAndroidTestPackage)
xamarin.android.runtimetests.TestInstrumentation
$(_MonoAndroidTestResultsPath)
$(MSBuildThisFileDirectory)timing-definitions-$(Configuration)$(_AotName).txt
-
+
-
+
diff --git a/src/Mono.Android/Test/Mono.Android-Tests.targets b/src/Mono.Android/Test/Mono.Android-Tests.targets
index 00d0be5a551..d1068ece991 100644
--- a/src/Mono.Android/Test/Mono.Android-Tests.targets
+++ b/src/Mono.Android/Test/Mono.Android-Tests.targets
@@ -8,7 +8,7 @@
-
+
-
+
+
diff --git a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/CreateAndroidEmulator.cs b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/CreateAndroidEmulator.cs
index 04e9453de95..463ba533070 100644
--- a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/CreateAndroidEmulator.cs
+++ b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/CreateAndroidEmulator.cs
@@ -21,7 +21,7 @@ public class CreateAndroidEmulator : Task
public string TargetId {get; set;}
- public string ImageName {get; set;} = "XamarinAndroidUnitTestRunner";
+ public string ImageName {get; set;} = "XamarinAndroidTestRunner";
public override bool Execute ()
{
diff --git a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/RunUITests.cs b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/RunUITests.cs
new file mode 100644
index 00000000000..9841efb6542
--- /dev/null
+++ b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/RunUITests.cs
@@ -0,0 +1,37 @@
+using Microsoft.Build.Framework;
+
+namespace Xamarin.Android.Tools.BootstrapTasks
+{
+ public class RunUITests : Adb
+ {
+ public string AdbTarget { get; set; }
+ public string AdbOptions { get; set; }
+
+ [Required]
+ public string Activity { get; set; }
+
+ protected override bool LogTaskMessages {
+ get { return false; }
+ }
+
+ public override bool Execute ()
+ {
+ Log.LogMessage (MessageImportance.Low, $"Task {nameof (RunUITests)}");
+ Log.LogMessage (MessageImportance.Low, $" {nameof (AdbTarget)}: {AdbTarget}");
+ Log.LogMessage (MessageImportance.Low, $" {nameof (AdbOptions)}: {AdbOptions}");
+ Log.LogMessage (MessageImportance.Low, $" {nameof (Activity)}: {Activity}");
+
+ base.Execute ();
+
+ Log.LogMessage(MessageImportance.Low, $" going to wait for 15 seconds");
+ System.Threading.Thread.Sleep (15000);
+
+ return !Log.HasLoggedErrors;
+ }
+
+ protected override string GenerateCommandLineCommands ()
+ {
+ return $"{AdbTarget} {AdbOptions} shell am start -n \"{Activity}\"";
+ }
+ }
+}
diff --git a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/StartAndroidEmulator.cs b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/StartAndroidEmulator.cs
index 2689ef45199..3fd4142b8bf 100644
--- a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/StartAndroidEmulator.cs
+++ b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/StartAndroidEmulator.cs
@@ -19,7 +19,7 @@ public class StartAndroidEmulator : Task
public string AndroidSdkHome {get; set;}
public string Port {get; set;}
- public string ImageName {get; set;} = "XamarinAndroidUnitTestRunner";
+ public string ImageName {get; set;} = "XamarinAndroidTestRunner";
public string ToolPath {get; set;}
public string ToolExe {get; set;}
diff --git a/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems b/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems
index 22e17d970c1..ea258a6242c 100644
--- a/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems
+++ b/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems
@@ -1,11 +1,11 @@
-
+
Xamarin.Android.JcwGen_Tests
xamarin.android.jcwgentests.TestInstrumentation
$(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Android.JcwGen_Tests.xml
$(MSBuildThisFileDirectory)..\..\..\build-tools\scripts\TimingDefinitions.txt
-
+
diff --git a/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.targets b/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.targets
index 97813d56aea..616a3a8e166 100644
--- a/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.targets
+++ b/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.targets
@@ -1,7 +1,7 @@
-
+
-Aot
-
+
+
AcquireAndroidTarget;
- UndeployUnitTestApks;
- DeployUnitTestApks;
- RunUnitTestApks;
+ UndeployTestApks;
+ DeployTestApks;
+ RunTestApks;
ReleaseAndroidTarget
diff --git a/tests/Xamarin.Forms-Performance-Integration/App.xaml b/tests/Xamarin.Forms-Performance-Integration/App.xaml
new file mode 100644
index 00000000000..15677dfdfe9
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/App.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+ #2196F3
+ #1976D2
+ #96d1ff
+ #FAFAFA
+ #C0C0C0
+ #4d4d4d
+ #999999
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/App.xaml.cs b/tests/Xamarin.Forms-Performance-Integration/App.xaml.cs
new file mode 100644
index 00000000000..d90dd6d63bc
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/App.xaml.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public partial class App : Application
+ {
+ public static bool UseMockDataStore = true;
+ public static string BackendUrl = "https://localhost:5000";
+
+ public App ()
+ {
+ InitializeComponent ();
+
+ if (UseMockDataStore)
+ DependencyService.Register ();
+ else
+ DependencyService.Register ();
+
+ if (Device.RuntimePlatform == Device.iOS)
+ MainPage = new MainPage ();
+ else
+ MainPage = new NavigationPage (new MainPage ());
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Assets/AboutAssets.txt b/tests/Xamarin.Forms-Performance-Integration/Droid/Assets/AboutAssets.txt
new file mode 100644
index 00000000000..a9b0638eb1b
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Assets/AboutAssets.txt
@@ -0,0 +1,19 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories) and given a Build Action of "AndroidAsset".
+
+These files will be deployed with your package and will be accessible using Android's
+AssetManager, like this:
+
+public class ReadAsset : Activity
+{
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ InputStream input = Assets.Open ("my_asset.txt");
+ }
+}
+
+Additionally, some Android functions will automatically load asset files:
+
+Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/MainActivity.cs b/tests/Xamarin.Forms-Performance-Integration/Droid/MainActivity.cs
new file mode 100644
index 00000000000..6397bf0f32d
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/MainActivity.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Android.App;
+using Android.Content;
+using Android.Content.PM;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Android.OS;
+
+namespace Xamarin.Forms.Performance.Integration.Droid
+{
+ [Activity (Icon = "@drawable/icon", Theme = "@style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
+ public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
+ {
+ bool firstOnCreate = true;
+ bool firstOnStart = true;
+ bool firstOnResume = true;
+
+ protected override void OnCreate (Bundle bundle)
+ {
+ if (firstOnCreate)
+ Console.WriteLine ("startup-timing: OnCreate reached");
+
+ TabLayoutResource = Resource.Layout.Tabbar;
+ ToolbarResource = Resource.Layout.Toolbar;
+
+ base.OnCreate (bundle);
+
+ global::Xamarin.Forms.Forms.Init (this, bundle);
+
+ LoadApplication (new App ());
+
+ if (firstOnCreate) {
+ Console.WriteLine ("startup-timing: OnCreate end reached");
+ firstOnCreate = false;
+ }
+ }
+
+ protected override void OnActivityResult (int requestCode, Result resultCode, Intent data)
+ {
+ base.OnActivityResult (requestCode, resultCode, data);
+ }
+
+ protected override void OnStart ()
+ {
+ if (firstOnStart)
+ Console.WriteLine ("startup-timing: OnStart reached");
+
+ base.OnStart ();
+
+ if (firstOnStart) {
+ Console.WriteLine ("startup-timing: OnStart end reached");
+ firstOnStart = false;
+ }
+ }
+
+ protected override void OnResume ()
+ {
+ if (firstOnResume)
+ Console.WriteLine ("startup-timing: OnResume reached");
+
+ base.OnResume ();
+
+ if (firstOnResume) {
+ Console.WriteLine ("startup-timing: OnResume end reached");
+ firstOnResume = false;
+ }
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Properties/AndroidManifest.xml b/tests/Xamarin.Forms-Performance-Integration/Droid/Properties/AndroidManifest.xml
new file mode 100644
index 00000000000..e9bec0891f9
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Properties/AssemblyInfo.cs b/tests/Xamarin.Forms-Performance-Integration/Droid/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000000..691e0b192ee
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Android.App;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle ("Xamarin.Forms.Performance.Integration.Droid")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("${AuthorCopyright}")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion ("1.0.0")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/AboutResources.txt b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/AboutResources.txt
new file mode 100644
index 00000000000..10f52d46021
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/AboutResources.txt
@@ -0,0 +1,44 @@
+Images, layout descriptions, binary blobs and string dictionaries can be included
+in your application as resource files. Various Android APIs are designed to
+operate on the resource IDs instead of dealing with images, strings or binary blobs
+directly.
+
+For example, a sample Android app that contains a user interface layout (main.axml),
+an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
+would keep its resources in the "Resources" directory of the application:
+
+Resources/
+ drawable/
+ icon.png
+
+ layout/
+ main.axml
+
+ values/
+ strings.xml
+
+In order to get the build system to recognize Android resources, set the build action to
+"AndroidResource". The native Android APIs do not operate directly with filenames, but
+instead operate on resource IDs. When you compile an Android application that uses resources,
+the build system will package the resources for distribution and generate a class called "R"
+(this is an Android convention) that contains the tokens for each one of the resources
+included. For example, for the above Resources layout, this is what the R class would expose:
+
+public class R {
+ public class drawable {
+ public const int icon = 0x123;
+ }
+
+ public class layout {
+ public const int main = 0x456;
+ }
+
+ public class strings {
+ public const int first_string = 0xabc;
+ public const int second_string = 0xbcd;
+ }
+}
+
+You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
+to reference the layout/main.axml file, or R.strings.first_string to reference the first
+string in the dictionary file values/strings.xml.
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-hdpi/icon.png b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-hdpi/icon.png
new file mode 100644
index 00000000000..964f110abb6
Binary files /dev/null and b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-hdpi/icon.png differ
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-xhdpi/icon.png b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-xhdpi/icon.png
new file mode 100644
index 00000000000..3c01e60ced0
Binary files /dev/null and b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-xhdpi/icon.png differ
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-xxhdpi/icon.png b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-xxhdpi/icon.png
new file mode 100644
index 00000000000..0d8c1c57dc5
Binary files /dev/null and b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable-xxhdpi/icon.png differ
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable/icon.png b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable/icon.png
new file mode 100644
index 00000000000..b0ba7150f4d
Binary files /dev/null and b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable/icon.png differ
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable/xamarin_logo.png b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable/xamarin_logo.png
new file mode 100644
index 00000000000..b36d00ed697
Binary files /dev/null and b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/drawable/xamarin_logo.png differ
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/layout/Tabbar.axml b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/layout/Tabbar.axml
new file mode 100644
index 00000000000..0bc7e9db671
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/layout/Tabbar.axml
@@ -0,0 +1,2 @@
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/layout/Toolbar.axml b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/layout/Toolbar.axml
new file mode 100644
index 00000000000..d685cbadba2
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/layout/Toolbar.axml
@@ -0,0 +1,2 @@
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/values/styles.xml b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/values/styles.xml
new file mode 100644
index 00000000000..7d6f9e578b4
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Resources/values/styles.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Xamarin.Forms.Performance.Integration.Droid.csproj b/tests/Xamarin.Forms-Performance-Integration/Droid/Xamarin.Forms.Performance.Integration.Droid.csproj
new file mode 100644
index 00000000000..49b90451ba8
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Xamarin.Forms.Performance.Integration.Droid.csproj
@@ -0,0 +1,121 @@
+
+
+
+ Debug
+ AnyCPU
+ {576312CC-83FF-48B1-A473-488CDC7121AD}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Xamarin.Forms.Performance.Integration.Droid
+ Xamarin.Forms.Performance.Integration.Droid
+ v7.1
+ True
+ Resources\Resource.designer.cs
+ Resource
+ Properties\AndroidManifest.xml
+ Resources
+ Assets
+ true
+
+
+ true
+ full
+ false
+ ..\..\..\bin\TestDebug
+ DEBUG;
+ prompt
+ 4
+ None
+
+
+ true
+ pdbonly
+ true
+ ..\..\..\bin\TestRelease
+ prompt
+ 4
+ true
+ false
+ armeabi-v7a;x86
+
+
+
+
+
+
+
+
+ ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll
+
+
+ ..\..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll
+
+
+ ..\..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll
+
+
+ ..\..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll
+
+
+ ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\FormsViewGroup.dll
+
+
+ ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Core.dll
+
+
+ ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll
+
+
+ ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.dll
+
+
+ ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/Xamarin.Forms.Performance.Integration.Droid.projitems b/tests/Xamarin.Forms-Performance-Integration/Droid/Xamarin.Forms.Performance.Integration.Droid.projitems
new file mode 100644
index 00000000000..24015c3e338
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/Xamarin.Forms.Performance.Integration.Droid.projitems
@@ -0,0 +1,11 @@
+
+
+
+
+ Xamarin.Forms_Performance_Integration
+ Xamarin.Forms_Performance_Integration/md52b709e14dec302485bbcaeac0bd817ce.MainActivity
+ $(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Forms_Test.xml
+ $(MSBuildThisFileDirectory)timing-definitions.txt
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/packages.config b/tests/Xamarin.Forms-Performance-Integration/Droid/packages.config
new file mode 100644
index 00000000000..dcda8dbc8f6
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/packages.config
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Xamarin.Forms-Performance-Integration/Droid/timing-definitions.txt b/tests/Xamarin.Forms-Performance-Integration/Droid/timing-definitions.txt
new file mode 100644
index 00000000000..5305a2f82ba
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Droid/timing-definitions.txt
@@ -0,0 +1,14 @@
+# measure time of last monodroid-timing message appearance
+last=monodroid-timing:\s+(?.*)$
+
+# measure time of runtime and JNIEnv initialization end
+init=monodroid-timing:\s+(?Runtime\.init: end native-to-managed.*)$
+JNI.init=monodroid-timing:\s+(?JNIEnv\.Initialize end:.*)$
+
+# measure UI startup
+OnCreateBegin=mono-stdout: startup-timing: (?OnCreate reached)$
+OnCreateEnd=mono-stdout: startup-timing: (?OnCreate end reached)$
+OnStartBegin=mono-stdout: startup-timing: (?OnStart reached)$
+OnStartEnd=mono-stdout: startup-timing: (?OnStart end reached)$
+OnResumeBegin=mono-stdout: startup-timing: (?OnResume reached)$
+OnResumeEnd=mono-stdout: startup-timing: (?OnResume end reached)$
diff --git a/tests/Xamarin.Forms-Performance-Integration/Models/Item.cs b/tests/Xamarin.Forms-Performance-Integration/Models/Item.cs
new file mode 100644
index 00000000000..d21a2759fc9
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Models/Item.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class Item
+ {
+ public string Id { get; set; }
+ public string Text { get; set; }
+ public string Description { get; set; }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Services/CloudDataStore.cs b/tests/Xamarin.Forms-Performance-Integration/Services/CloudDataStore.cs
new file mode 100644
index 00000000000..455557d5063
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Services/CloudDataStore.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+
+using Newtonsoft.Json;
+using Plugin.Connectivity;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class CloudDataStore : IDataStore-
+ {
+ HttpClient client;
+ IEnumerable
- items;
+
+ public CloudDataStore ()
+ {
+ client = new HttpClient ();
+ client.BaseAddress = new Uri ($"{App.BackendUrl}/");
+
+ items = new List
- ();
+ }
+
+ public async Task> GetItemsAsync (bool forceRefresh = false)
+ {
+ if (forceRefresh && CrossConnectivity.Current.IsConnected) {
+ var json = await client.GetStringAsync ($"api/item");
+ items = await Task.Run (() => JsonConvert.DeserializeObject> (json));
+ }
+
+ return items;
+ }
+
+ public async Task
- GetItemAsync (string id)
+ {
+ if (id != null && CrossConnectivity.Current.IsConnected) {
+ var json = await client.GetStringAsync ($"api/item/{id}");
+ return await Task.Run (() => JsonConvert.DeserializeObject
- (json));
+ }
+
+ return null;
+ }
+
+ public async Task AddItemAsync (Item item)
+ {
+ if (item == null || !CrossConnectivity.Current.IsConnected)
+ return false;
+
+ var serializedItem = JsonConvert.SerializeObject (item);
+
+ var response = await client.PostAsync ($"api/item", new StringContent (serializedItem, Encoding.UTF8, "application/json"));
+
+ return response.IsSuccessStatusCode;
+ }
+
+ public async Task UpdateItemAsync (Item item)
+ {
+ if (item == null || item.Id == null || !CrossConnectivity.Current.IsConnected)
+ return false;
+
+ var serializedItem = JsonConvert.SerializeObject (item);
+ var buffer = Encoding.UTF8.GetBytes (serializedItem);
+ var byteContent = new ByteArrayContent (buffer);
+
+ var response = await client.PutAsync (new Uri ($"api/item/{item.Id}"), byteContent);
+
+ return response.IsSuccessStatusCode;
+ }
+
+ public async Task DeleteItemAsync (string id)
+ {
+ if (string.IsNullOrEmpty (id) && !CrossConnectivity.Current.IsConnected)
+ return false;
+
+ var response = await client.DeleteAsync ($"api/item/{id}");
+
+ return response.IsSuccessStatusCode;
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Services/IDataStore.cs b/tests/Xamarin.Forms-Performance-Integration/Services/IDataStore.cs
new file mode 100644
index 00000000000..3857596c717
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Services/IDataStore.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public interface IDataStore
+ {
+ Task AddItemAsync (T item);
+ Task UpdateItemAsync (T item);
+ Task DeleteItemAsync (string id);
+ Task GetItemAsync (string id);
+ Task> GetItemsAsync (bool forceRefresh = false);
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Services/MockDataStore.cs b/tests/Xamarin.Forms-Performance-Integration/Services/MockDataStore.cs
new file mode 100644
index 00000000000..cd790ea261d
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Services/MockDataStore.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class MockDataStore : IDataStore
-
+ {
+ List
- items;
+
+ public MockDataStore ()
+ {
+ items = new List
- ();
+ var mockItems = new List
-
+ {
+ new Item { Id = Guid.NewGuid().ToString(), Text = "First item", Description="This is an item description." },
+ new Item { Id = Guid.NewGuid().ToString(), Text = "Second item", Description="This is an item description." },
+ new Item { Id = Guid.NewGuid().ToString(), Text = "Third item", Description="This is an item description." },
+ new Item { Id = Guid.NewGuid().ToString(), Text = "Fourth item", Description="This is an item description." },
+ new Item { Id = Guid.NewGuid().ToString(), Text = "Fifth item", Description="This is an item description." },
+ new Item { Id = Guid.NewGuid().ToString(), Text = "Sixth item", Description="This is an item description." },
+ };
+
+ foreach (var item in mockItems) {
+ items.Add (item);
+ }
+ }
+
+ public async Task AddItemAsync (Item item)
+ {
+ items.Add (item);
+
+ return await Task.FromResult (true);
+ }
+
+ public async Task UpdateItemAsync (Item item)
+ {
+ var _item = items.Where ((Item arg) => arg.Id == item.Id).FirstOrDefault ();
+ items.Remove (_item);
+ items.Add (item);
+
+ return await Task.FromResult (true);
+ }
+
+ public async Task DeleteItemAsync (string id)
+ {
+ var _item = items.Where ((Item arg) => arg.Id == id).FirstOrDefault ();
+ items.Remove (_item);
+
+ return await Task.FromResult (true);
+ }
+
+ public async Task
- GetItemAsync (string id)
+ {
+ return await Task.FromResult (items.FirstOrDefault (s => s.Id == id));
+ }
+
+ public async Task> GetItemsAsync (bool forceRefresh = false)
+ {
+ return await Task.FromResult (items);
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/ViewModels/AboutViewModel.cs b/tests/Xamarin.Forms-Performance-Integration/ViewModels/AboutViewModel.cs
new file mode 100644
index 00000000000..2a18cfd48d5
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/ViewModels/AboutViewModel.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Windows.Input;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class AboutViewModel : BaseViewModel
+ {
+ public AboutViewModel ()
+ {
+ Title = "About";
+
+ OpenWebCommand = new Command (() => Device.OpenUri (new Uri ("https://xamarin.com/platform")));
+ }
+
+ public ICommand OpenWebCommand { get; }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/ViewModels/BaseViewModel.cs b/tests/Xamarin.Forms-Performance-Integration/ViewModels/BaseViewModel.cs
new file mode 100644
index 00000000000..0a2a3323679
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/ViewModels/BaseViewModel.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class BaseViewModel : INotifyPropertyChanged
+ {
+ public IDataStore
- DataStore => DependencyService.Get> () ?? new MockDataStore ();
+
+ bool isBusy = false;
+ public bool IsBusy {
+ get { return isBusy; }
+ set { SetProperty (ref isBusy, value); }
+ }
+
+ string title = string.Empty;
+ public string Title {
+ get { return title; }
+ set { SetProperty (ref title, value); }
+ }
+
+ protected bool SetProperty (ref T backingStore, T value,
+ [CallerMemberName]string propertyName = "",
+ Action onChanged = null)
+ {
+ if (EqualityComparer.Default.Equals (backingStore, value))
+ return false;
+
+ backingStore = value;
+ onChanged?.Invoke ();
+ OnPropertyChanged (propertyName);
+ return true;
+ }
+
+ #region INotifyPropertyChanged
+ public event PropertyChangedEventHandler PropertyChanged;
+ protected void OnPropertyChanged ([CallerMemberName] string propertyName = "")
+ {
+ var changed = PropertyChanged;
+ if (changed == null)
+ return;
+
+ changed.Invoke (this, new PropertyChangedEventArgs (propertyName));
+ }
+ #endregion
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/ViewModels/ItemDetailViewModel.cs b/tests/Xamarin.Forms-Performance-Integration/ViewModels/ItemDetailViewModel.cs
new file mode 100644
index 00000000000..4239d93a849
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/ViewModels/ItemDetailViewModel.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class ItemDetailViewModel : BaseViewModel
+ {
+ public Item Item { get; set; }
+ public ItemDetailViewModel (Item item = null)
+ {
+ Title = item?.Text;
+ Item = item;
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/ViewModels/ItemsViewModel.cs b/tests/Xamarin.Forms-Performance-Integration/ViewModels/ItemsViewModel.cs
new file mode 100644
index 00000000000..a0ebba2fa6d
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/ViewModels/ItemsViewModel.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class ItemsViewModel : BaseViewModel
+ {
+ public ObservableCollection
- Items { get; set; }
+ public Command LoadItemsCommand { get; set; }
+
+ public ItemsViewModel ()
+ {
+ Title = "Browse";
+ Items = new ObservableCollection
- ();
+ LoadItemsCommand = new Command (async () => await ExecuteLoadItemsCommand ());
+
+ MessagingCenter.Subscribe (this, "AddItem", async (obj, item) => {
+ var _item = item as Item;
+ Items.Add (_item);
+ await DataStore.AddItemAsync (_item);
+ });
+ }
+
+ async Task ExecuteLoadItemsCommand ()
+ {
+ if (IsBusy)
+ return;
+
+ IsBusy = true;
+
+ try {
+ Items.Clear ();
+ var items = await DataStore.GetItemsAsync (true);
+ foreach (var item in items) {
+ Items.Add (item);
+ }
+ } catch (Exception ex) {
+ Debug.WriteLine (ex);
+ } finally {
+ IsBusy = false;
+ }
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/AboutPage.xaml b/tests/Xamarin.Forms-Performance-Integration/Views/AboutPage.xaml
new file mode 100644
index 00000000000..35ae053100c
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/AboutPage.xaml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/AboutPage.xaml.cs b/tests/Xamarin.Forms-Performance-Integration/Views/AboutPage.xaml.cs
new file mode 100644
index 00000000000..d8ed0a0cf14
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/AboutPage.xaml.cs
@@ -0,0 +1,14 @@
+using System;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public partial class AboutPage : ContentPage
+ {
+ public AboutPage ()
+ {
+ InitializeComponent ();
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/ItemDetailPage.xaml b/tests/Xamarin.Forms-Performance-Integration/Views/ItemDetailPage.xaml
new file mode 100644
index 00000000000..51456f40e58
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/ItemDetailPage.xaml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/ItemDetailPage.xaml.cs b/tests/Xamarin.Forms-Performance-Integration/Views/ItemDetailPage.xaml.cs
new file mode 100644
index 00000000000..072bde0e61c
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/ItemDetailPage.xaml.cs
@@ -0,0 +1,32 @@
+using System;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public partial class ItemDetailPage : ContentPage
+ {
+ ItemDetailViewModel viewModel;
+
+ // Note - The Xamarin.Forms Previewer requires a default, parameterless constructor to render a page.
+ public ItemDetailPage ()
+ {
+ InitializeComponent ();
+
+ var item = new Item {
+ Text = "Item 1",
+ Description = "This is an item description."
+ };
+
+ viewModel = new ItemDetailViewModel (item);
+ BindingContext = viewModel;
+ }
+
+ public ItemDetailPage (ItemDetailViewModel viewModel)
+ {
+ InitializeComponent ();
+
+ BindingContext = this.viewModel = viewModel;
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/ItemsPage.xaml b/tests/Xamarin.Forms-Performance-Integration/Views/ItemsPage.xaml
new file mode 100644
index 00000000000..5a657e78ee4
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/ItemsPage.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/ItemsPage.xaml.cs b/tests/Xamarin.Forms-Performance-Integration/Views/ItemsPage.xaml.cs
new file mode 100644
index 00000000000..ac587a9f8fc
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/ItemsPage.xaml.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public partial class ItemsPage : ContentPage
+ {
+ ItemsViewModel viewModel;
+
+ public ItemsPage ()
+ {
+ InitializeComponent ();
+
+ BindingContext = viewModel = new ItemsViewModel ();
+ }
+
+ async void OnItemSelected (object sender, SelectedItemChangedEventArgs args)
+ {
+ var item = args.SelectedItem as Item;
+ if (item == null)
+ return;
+
+ await Navigation.PushAsync (new ItemDetailPage (new ItemDetailViewModel (item)));
+
+ // Manually deselect item
+ ItemsListView.SelectedItem = null;
+ }
+
+ async void AddItem_Clicked (object sender, EventArgs e)
+ {
+ await Navigation.PushAsync (new NewItemPage ());
+ }
+
+ protected override void OnAppearing ()
+ {
+ base.OnAppearing ();
+
+ if (viewModel.Items.Count == 0)
+ viewModel.LoadItemsCommand.Execute (null);
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/MainPage.cs b/tests/Xamarin.Forms-Performance-Integration/Views/MainPage.cs
new file mode 100644
index 00000000000..42242fc1e59
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/MainPage.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public class MainPage : TabbedPage
+ {
+ public MainPage ()
+ {
+ Page itemsPage, aboutPage = null;
+
+ switch (Device.RuntimePlatform) {
+ case Device.iOS:
+ itemsPage = new NavigationPage (new ItemsPage ()) {
+ Title = "Browse"
+ };
+
+ aboutPage = new NavigationPage (new AboutPage ()) {
+ Title = "About"
+ };
+ itemsPage.Icon = "tab_feed.png";
+ aboutPage.Icon = "tab_about.png";
+ break;
+ default:
+ itemsPage = new ItemsPage () {
+ Title = "Browse"
+ };
+
+ aboutPage = new AboutPage () {
+ Title = "About"
+ };
+ break;
+ }
+
+ Children.Add (itemsPage);
+ Children.Add (aboutPage);
+
+ Title = Children [0].Title;
+ }
+
+ protected override void OnCurrentPageChanged ()
+ {
+ base.OnCurrentPageChanged ();
+ Title = CurrentPage?.Title ?? string.Empty;
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/NewItemPage.xaml b/tests/Xamarin.Forms-Performance-Integration/Views/NewItemPage.xaml
new file mode 100644
index 00000000000..85af613e686
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/NewItemPage.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Xamarin.Forms-Performance-Integration/Views/NewItemPage.xaml.cs b/tests/Xamarin.Forms-Performance-Integration/Views/NewItemPage.xaml.cs
new file mode 100644
index 00000000000..b746bd1f559
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Views/NewItemPage.xaml.cs
@@ -0,0 +1,29 @@
+using System;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Performance.Integration
+{
+ public partial class NewItemPage : ContentPage
+ {
+ public Item Item { get; set; }
+
+ public NewItemPage ()
+ {
+ InitializeComponent ();
+
+ Item = new Item {
+ Text = "Item name",
+ Description = "This is an item description."
+ };
+
+ BindingContext = this;
+ }
+
+ async void Save_Clicked (object sender, EventArgs e)
+ {
+ MessagingCenter.Send (this, "AddItem", Item);
+ await Navigation.PopToRootAsync ();
+ }
+ }
+}
diff --git a/tests/Xamarin.Forms-Performance-Integration/Xamarin.Forms.Performance.Integration.projitems b/tests/Xamarin.Forms-Performance-Integration/Xamarin.Forms.Performance.Integration.projitems
new file mode 100644
index 00000000000..bfa84e03004
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Xamarin.Forms.Performance.Integration.projitems
@@ -0,0 +1,44 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ {195BE9C2-1F91-40DC-BD6D-DE860BF083FB}
+
+
+ Xamarin.Forms.Performance.Integration
+
+
+
+
+
+
+
+
+
+
+
+
+ AboutPage.xaml
+
+
+ ItemDetailPage.xaml
+
+
+ ItemsPage.xaml
+
+
+ NewItemPage.xaml
+
+
+ App.xaml
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Xamarin.Forms-Performance-Integration/Xamarin.Forms.Performance.Integration.shproj b/tests/Xamarin.Forms-Performance-Integration/Xamarin.Forms.Performance.Integration.shproj
new file mode 100644
index 00000000000..a0ff92b3d5c
--- /dev/null
+++ b/tests/Xamarin.Forms-Performance-Integration/Xamarin.Forms.Performance.Integration.shproj
@@ -0,0 +1,11 @@
+
+
+
+ {195BE9C2-1F91-40DC-BD6D-DE860BF083FB}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj b/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
index 081374fa954..08364582ffd 100644
--- a/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
+++ b/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.csproj
@@ -70,7 +70,7 @@
-
+
diff --git a/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems b/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems
index 6639fcfe41c..204e62abda4 100644
--- a/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems
+++ b/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems
@@ -1,11 +1,11 @@
-
+
Xamarin.Android.Locale_Tests
xamarin.android.localetests.TestInstrumentation
$(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Android.Locale_Tests.xml
$(MSBuildThisFileDirectory)..\..\..\build-tools\scripts\TimingDefinitions.txt
-
+