[tests] Xamarin.Forms-Performance-Integration test (#818)

Add `tests/Xamarin.Forms-Performance-Integration` to measure UI app
startup times.

Add a new `<RunUITests/>` task to start an app/activity.

Rename `@(UnitTestApk)` to `@(TestApk)`, as it also handles UI tests.

Update `<ProcessLogcatTiming/>` to be able to process the
`adb logcat` output of started Android Activity processes.
This commit is contained in:
Radek Doulik 2017-09-07 18:35:08 +02:00 коммит произвёл Jonathan Pryor
Родитель 03407251f7
Коммит 09ba1ee45d
53 изменённых файлов: 1136 добавлений и 47 удалений

Просмотреть файл

@ -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:

Просмотреть файл

@ -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}

Просмотреть файл

@ -4,13 +4,14 @@
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.CheckAdbTarget" />
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.CreateAndroidEmulator" />
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.RunInstrumentationTests" />
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.RunUITests" />
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.StartAndroidEmulator" />
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.KillProcess" />
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\xa-prep-tasks.dll" TaskName="Xamarin.Android.BuildTools.PrepTasks.Sleep" />
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\xa-prep-tasks.dll" TaskName="Xamarin.Android.BuildTools.PrepTasks.ProcessLogcatTiming" />
<PropertyGroup>
<_TestImageName>XamarinAndroidUnitTestRunner</_TestImageName>
<_TestImageName>XamarinAndroidTestRunner</_TestImageName>
<_AdbEmulatorPort>5570</_AdbEmulatorPort>
</PropertyGroup>
@ -107,54 +108,62 @@
<!--
<ItemGroup>
<UnitTestApk Include="ApkFile">
<TestApk Include="ApkFile">
<Package></Package>
<InstrumentationType></InstrumentationType>
<ResultsPath></ResultsPath>
</UnitTestApk>
</TestApk>
</ItemGroup>
-->
<Target Name="DeployUnitTestApks"
Condition=" '@(UnitTestApk)' != '' ">
<Target Name="DeployTestApks"
Condition=" '@(TestApk)' != '' ">
<Xamarin.Android.Tools.BootstrapTasks.Adb
Arguments="$(_AdbTarget) $(AdbOptions) install &quot;%(UnitTestApk.Identity)&quot;"
Arguments="$(_AdbTarget) $(AdbOptions) install &quot;%(TestApk.Identity)&quot;"
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)"
/>
</Target>
<Target Name="UndeployUnitTestApks"
Condition=" '@(UnitTestApk)' != '' ">
<Target Name="UndeployTestApks"
Condition=" '@(TestApk)' != '' ">
<Xamarin.Android.Tools.BootstrapTasks.Adb
Arguments="$(_AdbTarget) $(AdbOptions) uninstall &quot;%(UnitTestApk.Package)&quot;"
Arguments="$(_AdbTarget) $(AdbOptions) uninstall &quot;%(TestApk.Package)&quot;"
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)"
/>
</Target>
<Target Name="RunUnitTestApks"
Condition=" '@(UnitTestApk)' != '' ">
<Target Name="RunTestApks"
Condition=" '@(TestApk)' != '' ">
<RunInstrumentationTests
Condition=" '%(TestApk.InstrumentationType)' != ''"
AdbTarget="$(_AdbTarget)"
AdbOptions="$(AdbOptions)"
Component="%(UnitTestApk.Package)/%(UnitTestApk.InstrumentationType)"
NUnit2TestResultsFile="%(UnitTestApk.ResultsPath)"
Component="%(TestApk.Package)/%(TestApk.InstrumentationType)"
NUnit2TestResultsFile="%(TestApk.ResultsPath)"
TestFixture="$(TestFixture)"
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)">
<Output TaskParameter="FailedToRun" ItemName="_FailedComponent"/>
</RunInstrumentationTests>
<RunUITests
Condition=" '%(TestApk.Activity)' != '' "
AdbTarget="$(_AdbTarget)"
AdbOptions="$(AdbOptions)"
Activity="%(TestApk.Activity)">
</RunUITests>
<PropertyGroup>
<_LogcatFilename>logcat-$(Configuration)$(_AotName).txt</_LogcatFilename>
</PropertyGroup>
<Exec Command="&quot;$(AdbToolPath)\$(AdbToolExe)&quot; $(_AdbTarget) $(AdbOptions) logcat -v threadtime -d > $(_LogcatFilename)" />
<ProcessLogcatTiming
Condition=" '%(UnitTestApk.TimingDefinitionsFilename)' != '' "
Condition=" '%(TestApk.TimingDefinitionsFilename)' != '' "
InputFilename="$(_LogcatFilename)"
ApplicationPackageName="%(UnitTestApk.Package)"
ResultsFilename="%(UnitTestApk.ResultsPath)"
DefinitionsFilename="%(UnitTestApk.TimingDefinitionsFilename)"
AddResults="true" />
ApplicationPackageName="%(TestApk.Package)"
ResultsFilename="%(TestApk.ResultsPath)"
DefinitionsFilename="%(TestApk.TimingDefinitionsFilename)"
AddResults="true"
Activity="%(TestApk.Activity)" />
</Target>
</Project>

Просмотреть файл

@ -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 ($@"^(?<timestamp>\d+-\d+\s+[\d:\.]+)\s+.*ActivityManager: Start proc.*for added application {ApplicationPackageName}: pid=(?<pid>\d+)");
var procIdentification = string.IsNullOrEmpty (Activity) ? $"added application {ApplicationPackageName}" : $"activity {Activity}";
var procStartRegex = new Regex ($@"^(?<timestamp>\d+-\d+\s+[\d:\.]+)\s+.*ActivityManager: Start proc.*for {procIdentification}: pid=(?<pid>\d+)");
Regex timingRegex = null;
DateTime start = DateTime.Now;
DateTime last = start;

Просмотреть файл

@ -8,14 +8,14 @@
<_MonoAndroidTestApkSizesInput>apk-sizes-$(_MonoAndroidTestPackage)-$(Configuration)$(_AotName).txt</_MonoAndroidTestApkSizesInput>
</PropertyGroup>
<ItemGroup>
<UnitTestApk Include="$(_MonoAndroidTestApkFile)">
<TestApk Include="$(_MonoAndroidTestApkFile)">
<Package>$(_MonoAndroidTestPackage)</Package>
<InstrumentationType>xamarin.android.runtimetests.TestInstrumentation</InstrumentationType>
<ResultsPath>$(_MonoAndroidTestResultsPath)</ResultsPath>
<TimingDefinitionsFilename>$(MSBuildThisFileDirectory)timing-definitions-$(Configuration)$(_AotName).txt</TimingDefinitionsFilename>
</UnitTestApk>
</TestApk>
</ItemGroup>
<Target Name="_RecordApkSizes" AfterTargets="DeployUnitTestApks">
<Target Name="_RecordApkSizes" AfterTargets="DeployTestApks">
<Delete Files="$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests-values.csv;$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests-times.csv" Condition=" '$(Configuration)' == 'Debug' " />
<Exec Condition=" '$(HostOS)' == 'Darwin' " Command="stat -f &quot;stat: %z %N&quot; &quot;$(_MonoAndroidTestApkFile)&quot; > $(_MonoAndroidTestApkSizesInput)" />
<Exec Condition=" '$(HostOS)' == 'Linux' " Command="stat -c &quot;stat: %s %N&quot; &quot;$(_MonoAndroidTestApkFile)&quot; > $(_MonoAndroidTestApkSizesInput)" />

Просмотреть файл

@ -8,7 +8,7 @@
<AndroidNativeLibrary Include="libs\x86_64\libreuse-threads.so" />
</ItemGroup>
<Import Project="Mono.Android-Tests.projitems" />
<Import Project="..\..\..\build-tools\scripts\UnitTestApks.targets" />
<Import Project="..\..\..\build-tools\scripts\TestApks.targets" />
<Target Name="BuildNativeLibs"
BeforeTargets="Build"
DependsOnTargets="AndroidPrepareForBuild"

Просмотреть файл

@ -46,11 +46,12 @@
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\GenerateMonoDroidIncludes.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\GenerateProfile.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\GetNugetPackageBasePath.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\RunInstrumentationTests.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\StartAndroidEmulator.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\UnzipDirectoryChildren.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\Zip.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\KillProcess.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\RunUITests.cs" />
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\RunInstrumentationTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\external\LibZipSharp\libZipSharp.csproj">

Просмотреть файл

@ -21,7 +21,7 @@ namespace Xamarin.Android.Tools.BootstrapTasks
public string TargetId {get; set;}
public string ImageName {get; set;} = "XamarinAndroidUnitTestRunner";
public string ImageName {get; set;} = "XamarinAndroidTestRunner";
public override bool Execute ()
{

Просмотреть файл

@ -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}\"";
}
}
}

Просмотреть файл

@ -19,7 +19,7 @@ namespace Xamarin.Android.Tools.BootstrapTasks
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;}

Просмотреть файл

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<UnitTestApk Include="$(OutputPath)Xamarin.Android.JcwGen_Tests-Signed.apk">
<TestApk Include="$(OutputPath)Xamarin.Android.JcwGen_Tests-Signed.apk">
<Package>Xamarin.Android.JcwGen_Tests</Package>
<InstrumentationType>xamarin.android.jcwgentests.TestInstrumentation</InstrumentationType>
<ResultsPath>$(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Android.JcwGen_Tests.xml</ResultsPath>
<TimingDefinitionsFilename>$(MSBuildThisFileDirectory)..\..\..\build-tools\scripts\TimingDefinitions.txt</TimingDefinitionsFilename>
</UnitTestApk>
</TestApk>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Xamarin.Android.JcwGen-Tests.projitems" />
<Import Project="..\..\..\build-tools\scripts\UnitTestApks.targets" />
<Import Project="..\..\..\build-tools\scripts\TestApks.targets" />
<Target Name="BuildNativeLibs"
DependsOnTargets="AndroidPrepareForBuild"
Inputs="jni\Android.mk;jni\timing.c"

Просмотреть файл

@ -9,19 +9,20 @@
<_AotName Condition=" '$(AotAssemblies)' == 'true' ">-Aot</_AotName>
</PropertyGroup>
<!--
Note that the `.csproj` for each `@(UnitTestApk)` entry *must* be added to
Note that the `.csproj` for each `@(TestApk)` entry *must* be added to
`$(TEST_APK_PROJECTS)` in the toplevel Makefile so that the `.apk` is built.
-->
<Import Project="..\src\Mono.Android\Test\Mono.Android-Tests.projitems" />
<Import Project="..\tests\CodeGen-Binding\Xamarin.Android.JcwGen-Tests\Xamarin.Android.JcwGen-Tests.projitems" Condition=" '$(Configuration)' == 'Debug' " />
<Import Project="..\tests\locales\Xamarin.Android.Locale-Tests\Xamarin.Android.Locale-Tests.projitems" Condition=" '$(Configuration)' == 'Debug' " />
<Import Project="..\build-tools\scripts\UnitTestApks.targets" />
<Import Project="..\tests\Xamarin.Forms-Performance-Integration\Droid\Xamarin.Forms.Performance.Integration.Droid.projitems" Condition=" '$(Configuration)' == 'Release' " />
<Import Project="..\build-tools\scripts\TestApks.targets" />
<PropertyGroup>
<RunApkTestsDependsOn>
AcquireAndroidTarget;
UndeployUnitTestApks;
DeployUnitTestApks;
RunUnitTestApks;
UndeployTestApks;
DeployTestApks;
RunTestApks;
ReleaseAndroidTarget
</RunApkTestsDependsOn>
</PropertyGroup>

Просмотреть файл

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Performance.Integration.App">
<Application.Resources>
<ResourceDictionary>
<Color x:Key="Primary">#2196F3</Color>
<Color x:Key="PrimaryDark">#1976D2</Color>
<Color x:Key="Accent">#96d1ff</Color>
<Color x:Key="LightBackgroundColor">#FAFAFA</Color>
<Color x:Key="DarkBackgroundColor">#C0C0C0</Color>
<Color x:Key="MediumGrayTextColor">#4d4d4d</Color>
<Color x:Key="LightTextColor">#999999</Color>
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="{StaticResource Primary}" />
<Setter Property="BarTextColor" Value="White" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

Просмотреть файл

@ -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<MockDataStore> ();
else
DependencyService.Register<CloudDataStore> ();
if (Device.RuntimePlatform == Device.iOS)
MainPage = new MainPage ();
else
MainPage = new NavigationPage (new MainPage ());
}
}
}

Просмотреть файл

@ -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");

Просмотреть файл

@ -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;
}
}
}
}

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="Xamarin.Forms_Performance_Integration">
<uses-sdk android:minSdkVersion="15" />
<application android:label="Xamarin.Forms.Performance.Integration"></application>
</manifest>

Просмотреть файл

@ -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("")]

Просмотреть файл

@ -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.

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.3 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 21 KiB

Просмотреть файл

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:tabIndicatorColor="@android:color/white" app:tabGravity="fill" app:tabMode="fixed" />

Просмотреть файл

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Просмотреть файл

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<style name="MyTheme" parent="MyTheme.Base">
</style>
<!-- Base theme applied no matter what API -->
<style name="MyTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
<item name="windowNoTitle">true</item>
<!--We will be using the toolbar so no need to show ActionBar-->
<item name="windowActionBar">false</item>
<!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette-->
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">#2196F3</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#1976D2</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#FF4081</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight and colorSwitchThumbNormal. -->
<item name="windowActionModeOverlay">true</item>
<item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
</style>
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#FF4081</item>
</style>
</resources>

Просмотреть файл

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{576312CC-83FF-48B1-A473-488CDC7121AD}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<RootNamespace>Xamarin.Forms.Performance.Integration.Droid</RootNamespace>
<AssemblyName>Xamarin.Forms.Performance.Integration.Droid</AssemblyName>
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
<AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\bin\TestDebug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\..\bin\TestRelease</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidManagedSymbols>true</AndroidManagedSymbols>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
<Reference Include="System.Net.Http" />
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity.Abstractions">
<HintPath>..\..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity">
<HintPath>..\..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v4">
<HintPath>..\..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Vector.Drawable">
<HintPath>..\..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<HintPath>..\..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.RecyclerView">
<HintPath>..\..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.AppCompat">
<HintPath>..\..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Design">
<HintPath>..\..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.CardView">
<HintPath>..\..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.MediaRouter">
<HintPath>..\..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
</Reference>
<Reference Include="FormsViewGroup">
<HintPath>..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Core">
<HintPath>..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform.Android">
<HintPath>..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform">
<HintPath>..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml">
<HintPath>..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="Assets\AboutAssets.txt" />
<None Include="Properties\AndroidManifest.xml" />
<None Include="Resources\AboutResources.txt" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="MainActivity.cs" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\icon.png" />
<AndroidResource Include="Resources\drawable\xamarin_logo.png" />
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
<AndroidResource Include="Resources\drawable-xhdpi\icon.png" />
<AndroidResource Include="Resources\drawable-xxhdpi\icon.png" />
<AndroidResource Include="Resources\layout\Tabbar.axml" />
<AndroidResource Include="Resources\layout\Toolbar.axml" />
<AndroidResource Include="Resources\values\styles.xml" />
</ItemGroup>
<Import Project="..\Xamarin.Forms.Performance.Integration.projitems" Label="Shared" Condition="Exists('..\Xamarin.Forms.Performance.Integration.projitems')" />
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Import Project="..\..\..\packages\Xamarin.Forms.2.3.4.247\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\..\packages\Xamarin.Forms.2.3.4.247\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
</Project>

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<TestApk Include="$(OutputPath)Xamarin.Forms_Performance_Integration-Signed.apk">
<Package>Xamarin.Forms_Performance_Integration</Package>
<Activity>Xamarin.Forms_Performance_Integration/md52b709e14dec302485bbcaeac0bd817ce.MainActivity</Activity>
<ResultsPath>$(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Forms_Test.xml</ResultsPath>
<TimingDefinitionsFilename>$(MSBuildThisFileDirectory)timing-definitions.txt</TimingDefinitionsFilename>
</TestApk>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="monoandroid71" />
<package id="Xam.Plugin.Connectivity" version="2.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.v4" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.v7.AppCompat" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.v7.CardView" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.v7.MediaRouter" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.v7.RecyclerView" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.Vector.Drawable" version="23.3.0" targetFramework="monoandroid71" />
<package id="Xamarin.Forms" version="2.3.4.247" targetFramework="monoandroid71" />
</packages>

Просмотреть файл

@ -0,0 +1,14 @@
# measure time of last monodroid-timing message appearance
last=monodroid-timing:\s+(?<message>.*)$
# measure time of runtime and JNIEnv initialization end
init=monodroid-timing:\s+(?<message>Runtime\.init: end native-to-managed.*)$
JNI.init=monodroid-timing:\s+(?<message>JNIEnv\.Initialize end:.*)$
# measure UI startup
OnCreateBegin=mono-stdout: startup-timing: (?<message>OnCreate reached)$
OnCreateEnd=mono-stdout: startup-timing: (?<message>OnCreate end reached)$
OnStartBegin=mono-stdout: startup-timing: (?<message>OnStart reached)$
OnStartEnd=mono-stdout: startup-timing: (?<message>OnStart end reached)$
OnResumeBegin=mono-stdout: startup-timing: (?<message>OnResume reached)$
OnResumeEnd=mono-stdout: startup-timing: (?<message>OnResume end reached)$

Просмотреть файл

@ -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; }
}
}

Просмотреть файл

@ -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<Item>
{
HttpClient client;
IEnumerable<Item> items;
public CloudDataStore ()
{
client = new HttpClient ();
client.BaseAddress = new Uri ($"{App.BackendUrl}/");
items = new List<Item> ();
}
public async Task<IEnumerable<Item>> GetItemsAsync (bool forceRefresh = false)
{
if (forceRefresh && CrossConnectivity.Current.IsConnected) {
var json = await client.GetStringAsync ($"api/item");
items = await Task.Run (() => JsonConvert.DeserializeObject<IEnumerable<Item>> (json));
}
return items;
}
public async Task<Item> GetItemAsync (string id)
{
if (id != null && CrossConnectivity.Current.IsConnected) {
var json = await client.GetStringAsync ($"api/item/{id}");
return await Task.Run (() => JsonConvert.DeserializeObject<Item> (json));
}
return null;
}
public async Task<bool> 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<bool> 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<bool> DeleteItemAsync (string id)
{
if (string.IsNullOrEmpty (id) && !CrossConnectivity.Current.IsConnected)
return false;
var response = await client.DeleteAsync ($"api/item/{id}");
return response.IsSuccessStatusCode;
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Xamarin.Forms.Performance.Integration
{
public interface IDataStore<T>
{
Task<bool> AddItemAsync (T item);
Task<bool> UpdateItemAsync (T item);
Task<bool> DeleteItemAsync (string id);
Task<T> GetItemAsync (string id);
Task<IEnumerable<T>> GetItemsAsync (bool forceRefresh = false);
}
}

Просмотреть файл

@ -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<Item>
{
List<Item> items;
public MockDataStore ()
{
items = new List<Item> ();
var mockItems = new List<Item>
{
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<bool> AddItemAsync (Item item)
{
items.Add (item);
return await Task.FromResult (true);
}
public async Task<bool> 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<bool> DeleteItemAsync (string id)
{
var _item = items.Where ((Item arg) => arg.Id == id).FirstOrDefault ();
items.Remove (_item);
return await Task.FromResult (true);
}
public async Task<Item> GetItemAsync (string id)
{
return await Task.FromResult (items.FirstOrDefault (s => s.Id == id));
}
public async Task<IEnumerable<Item>> GetItemsAsync (bool forceRefresh = false)
{
return await Task.FromResult (items);
}
}
}

Просмотреть файл

@ -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; }
}
}

Просмотреть файл

@ -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<Item> DataStore => DependencyService.Get<IDataStore<Item>> () ?? 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<T> (ref T backingStore, T value,
[CallerMemberName]string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.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
}
}

Просмотреть файл

@ -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;
}
}
}

Просмотреть файл

@ -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<Item> Items { get; set; }
public Command LoadItemsCommand { get; set; }
public ItemsViewModel ()
{
Title = "Browse";
Items = new ObservableCollection<Item> ();
LoadItemsCommand = new Command (async () => await ExecuteLoadItemsCommand ());
MessagingCenter.Subscribe<NewItemPage, Item> (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;
}
}
}
}

Просмотреть файл

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Performance.Integration.AboutPage" xmlns:vm="clr-namespace:Xamarin.Forms.Performance.Integration;" Title="{Binding Title}">
<ContentPage.BindingContext>
<vm:AboutViewModel />
</ContentPage.BindingContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout BackgroundColor="{StaticResource Accent}" VerticalOptions="FillAndExpand" HorizontalOptions="Fill">
<StackLayout Orientation="Horizontal" HorizontalOptions="Center" VerticalOptions="Center">
<ContentView Padding="0,40,0,40" VerticalOptions="FillAndExpand">
<Image Source="xamarin_logo.png" VerticalOptions="Center" HeightRequest="64" />
</ContentView>
</StackLayout>
</StackLayout>
<ScrollView Grid.Row="1">
<StackLayout Orientation="Vertical" Padding="16,40,16,40" Spacing="10">
<Label FontSize="22">
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="AppName" FontAttributes="Bold" FontSize="22" />
<Span Text=" " />
<Span Text="1.0" ForegroundColor="{StaticResource LightTextColor}" />
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
<Label>
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="This app is written in C# and native APIs using the" />
<Span Text=" " />
<Span Text="Xamarin Platform" FontAttributes="Bold" />
<Span Text="." />
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
<Label>
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="It shares code with its" />
<Span Text=" " />
<Span Text="iOS, Android, and Windows" FontAttributes="Bold" />
<Span Text=" " />
<Span Text="versions." />
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
<Button Margin="0,10,0,0" Text="Learn more" Command="{Binding OpenWebCommand}" BackgroundColor="{StaticResource Primary}" TextColor="White" />
</StackLayout>
</ScrollView>
</Grid>
</ContentPage>

Просмотреть файл

@ -0,0 +1,14 @@
using System;
using Xamarin.Forms;
namespace Xamarin.Forms.Performance.Integration
{
public partial class AboutPage : ContentPage
{
public AboutPage ()
{
InitializeComponent ();
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Performance.Integration.ItemDetailPage" Title="{Binding Title}">
<StackLayout Spacing="20" Padding="15">
<Label Text="{Binding Item.Text}" FontSize="Medium" />
<Label Text="{Binding Item.Description}" FontSize="Small" />
</StackLayout>
</ContentPage>

Просмотреть файл

@ -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;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Performance.Integration.ItemsPage" Title="{Binding Title}" x:Name="BrowseItemsPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ItemsListView" ItemsSource="{Binding Items}" VerticalOptions="FillAndExpand" HasUnevenRows="true" RefreshCommand="{Binding LoadItemsCommand}" IsPullToRefreshEnabled="true" IsRefreshing="{Binding IsBusy, Mode=OneWay}" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding Text}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemTextStyle}" FontSize="16" />
<Label Text="{Binding Description}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemDetailTextStyle}" FontSize="13" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>

Просмотреть файл

@ -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);
}
}
}

Просмотреть файл

@ -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;
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Performance.Integration.NewItemPage" Title="New Item">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Save" Clicked="Save_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Spacing="20" Padding="15">
<Label Text="Text" FontSize="Medium" />
<Entry Text="{Binding Item.Text}" FontSize="Small" />
<Label Text="Description" FontSize="Medium" />
<Editor Text="{Binding Item.Description}" FontSize="Small" Margin="0" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Просмотреть файл

@ -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 ();
}
}
}

Просмотреть файл

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>{195BE9C2-1F91-40DC-BD6D-DE860BF083FB}</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Xamarin.Forms.Performance.Integration</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Models\Item.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\CloudDataStore.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\IDataStore.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\MockDataStore.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\AboutViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\BaseViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ItemDetailViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ItemsViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Views\MainPage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Views\AboutPage.xaml.cs">
<DependentUpon>AboutPage.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Views\ItemDetailPage.xaml.cs">
<DependentUpon>ItemDetailPage.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Views\ItemsPage.xaml.cs">
<DependentUpon>ItemsPage.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Views\NewItemPage.xaml.cs">
<DependentUpon>NewItemPage.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\AboutPage.xaml" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\ItemDetailPage.xaml" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\ItemsPage.xaml" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\NewItemPage.xaml" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)App.xaml" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{195BE9C2-1F91-40DC-BD6D-DE860BF083FB}</ProjectGuid>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import Project="Xamarin.Forms.Performance.Integration.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

Просмотреть файл

@ -70,7 +70,7 @@
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="Xamarin.Android.Locale-Tests.projitems" />
<Import Project="..\..\..\build-tools\scripts\UnitTestApks.targets" />
<Import Project="..\..\..\build-tools\scripts\TestApks.targets" />
<ItemGroup>
<EmbeddedResource Include="strings.de-DE.resx" />
<EmbeddedResource Include="strings.fr-FR.resx" />

Просмотреть файл

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<UnitTestApk Include="$(OutputPath)Xamarin.Android.Locale_Tests-Signed.apk">
<TestApk Include="$(OutputPath)Xamarin.Android.Locale_Tests-Signed.apk">
<Package>Xamarin.Android.Locale_Tests</Package>
<InstrumentationType>xamarin.android.localetests.TestInstrumentation</InstrumentationType>
<ResultsPath>$(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Android.Locale_Tests.xml</ResultsPath>
<TimingDefinitionsFilename>$(MSBuildThisFileDirectory)..\..\..\build-tools\scripts\TimingDefinitions.txt</TimingDefinitionsFilename>
</UnitTestApk>
</TestApk>
</ItemGroup>
</Project>