diff --git a/Perspex.sln b/Perspex.sln
index 268cc1c87c..fab898d95e 100644
--- a/Perspex.sln
+++ b/Perspex.sln
@@ -114,17 +114,23 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.Desktop", "src
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.RenderTests", "tests\Perspex.RenderTests\Perspex.Skia.RenderTests.csproj", "{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.Android", "src\Skia\Perspex.Skia.Android\Perspex.Skia.Android.csproj", "{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.Android.TestApp", "src\Skia\Perspex.Skia.Android.TestApp\Perspex.Skia.Android.TestApp.csproj", "{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4
- src\Skia\Perspex.Skia\Perspex.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
+ src\Skia\Perspex.Skia\Perspex.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
+ src\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
+ src\Skia\Perspex.Skia\Perspex.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -284,6 +290,13 @@ Global
{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -317,5 +330,7 @@ Global
{2F59F3D0-748D-4652-B01E-E0D954756308} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{925DD807-B651-475F-9F7C-CBEB974CE43D} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{D35A9F3D-8BB0-496E-BF72-444038A7DEBB} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+ {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
+ {F92E55A5-ED73-4CCB-AB4B-0541B6757F31} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
EndGlobalSection
EndGlobal
diff --git a/src/Shared/RenderHelpers/ArcToHelper.cs b/src/Shared/RenderHelpers/ArcToHelper.cs
index a708c09ee2..b03b85b227 100644
--- a/src/Shared/RenderHelpers/ArcToHelper.cs
+++ b/src/Shared/RenderHelpers/ArcToHelper.cs
@@ -47,7 +47,6 @@
// as these may be helpful for debugging.
using System;
-using System.Media;
using Perspex.Media;
using Perspex.Platform;
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/MainActivity.cs b/src/Skia/Perspex.Skia.Android.TestApp/MainActivity.cs
new file mode 100644
index 0000000000..b2c4244b4e
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android.TestApp/MainActivity.cs
@@ -0,0 +1,71 @@
+using System;
+using Android.App;
+using Android.Content;
+using Android.Graphics;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Android.OS;
+using Android.Util;
+using Perspex.Media;
+using Perspex.Platform;
+using Perspex;
+
+namespace Perspex.Skia.Android.TestApp
+{
+ [Activity(Label = "Perspex.Skia.Android.TestApp", MainLauncher = true, Icon = "@drawable/icon")]
+ public class MainActivity : Activity
+ {
+
+ protected override void OnCreate(Bundle bundle)
+ {
+ base.OnCreate(bundle);
+ SetContentView(new MainView(this));
+ }
+
+ class MainView : SkiaView
+ {
+ float _radians = 0;
+ public MainView(Activity context) : base(context)
+ {
+ }
+
+ protected override void OnRender(DrawingContext ctx)
+ {
+ ctx.FillRectangle(Brushes.Green, new Rect(0, 0, Width, Height));
+
+ var rc = new Rect(0, 0, Width/3, Height/3);
+ using (ctx.PushPostTransform(
+ Perspex.Matrix.CreateTranslation(-Width/6, -Width/6)*
+ Perspex.Matrix.CreateRotation(_radians)*
+ Perspex.Matrix.CreateTranslation(Width/2, Height/2)))
+ {
+ ctx.FillRectangle(new LinearGradientBrush()
+ {
+ GradientStops =
+ {
+ new GradientStop() {Color = Colors.Blue},
+ new GradientStop(Colors.Red, 1)
+ }
+ }, rc, 5);
+ }
+
+
+ }
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ if (e.Action == MotionEventActions.Down)
+ return true;
+ if (e.Action == MotionEventActions.Move)
+ {
+ _radians = (e.RawY + e.RawY)/100;
+ Invalidate();
+ return true;
+ }
+ return base.OnTouchEvent(e);
+ }
+ }
+ }
+}
+
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj b/src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj
new file mode 100644
index 0000000000..36cb4b0e0b
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj
@@ -0,0 +1,122 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ Perspex.Skia.Android.TestApp
+ Perspex.Skia.Android.TestApp
+ 512
+ true
+ Resources\Resource.Designer.cs
+ Off
+ True
+ v5.0
+ Properties\AndroidManifest.xml
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ False
+ None
+
+ True
+ False
+ False
+ armeabi-v7a,x86
+
+
+ Xamarin
+ False
+ True
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ False
+ SdkOnly
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {d211e587-d8bc-45b9-95a4-f297c8fa5200}
+ Perspex.Animation
+
+
+ {b09b78d8-9b26-48b0-9149-d64a2f120f3f}
+ Perspex.Base
+
+
+ {d2221c82-4a25-4583-9b43-d791e3f6820c}
+ Perspex.Controls
+
+
+ {62024b2d-53eb-4638-b26b-85eeaa54866e}
+ Perspex.Input
+
+
+ {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}
+ Perspex.Interactivity
+
+
+ {42472427-4774-4c81-8aff-9f27b8e31721}
+ Perspex.Layout
+
+
+ {eb582467-6abb-43a1-b052-e981ba910e3a}
+ Perspex.SceneGraph
+
+
+ {f1baa01a-f176-4c6a-b39d-5b40bb1b148f}
+ Perspex.Styling
+
+
+ {bd43f7c0-396b-4aa1-bad9-dfde54d51298}
+ Perspex.Skia.Android
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/Properties/AndroidManifest.xml b/src/Skia/Perspex.Skia.Android.TestApp/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..7851069428
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android.TestApp/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/Properties/AssemblyInfo.cs b/src/Skia/Perspex.Skia.Android.TestApp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..91f8f0aff6
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android.TestApp/Properties/AssemblyInfo.cs
@@ -0,0 +1,30 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Android.App;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Perspex.Skia.Android.TestApp")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Perspex.Skia.Android.TestApp")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/Resources/Resource.Designer.cs b/src/Skia/Perspex.Skia.Android.TestApp/Resources/Resource.Designer.cs
new file mode 100644
index 0000000000..948db70042
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android.TestApp/Resources/Resource.Designer.cs
@@ -0,0 +1,112 @@
+#pragma warning disable 1591
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+[assembly: global::Android.Runtime.ResourceDesignerAttribute("Perspex.Skia.Android.TestApp.Resource", IsApplication=true)]
+
+namespace Perspex.Skia.Android.TestApp
+{
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+ public partial class Resource
+ {
+
+ static Resource()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ public static void UpdateIdValues()
+ {
+ }
+
+ public partial class Attribute
+ {
+
+ static Attribute()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Attribute()
+ {
+ }
+ }
+
+ public partial class Drawable
+ {
+
+ // aapt resource value: 0x7f020000
+ public const int Icon = 2130837504;
+
+ static Drawable()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Drawable()
+ {
+ }
+ }
+
+ public partial class Id
+ {
+
+ // aapt resource value: 0x7f050000
+ public const int MyButton = 2131034112;
+
+ static Id()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Id()
+ {
+ }
+ }
+
+ public partial class Layout
+ {
+
+ // aapt resource value: 0x7f030000
+ public const int Main = 2130903040;
+
+ static Layout()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Layout()
+ {
+ }
+ }
+
+ public partial class String
+ {
+
+ // aapt resource value: 0x7f040001
+ public const int ApplicationName = 2130968577;
+
+ // aapt resource value: 0x7f040000
+ public const int Hello = 2130968576;
+
+ static String()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private String()
+ {
+ }
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/Resources/drawable/Icon.png b/src/Skia/Perspex.Skia.Android.TestApp/Resources/drawable/Icon.png
new file mode 100644
index 0000000000..8074c4c571
Binary files /dev/null and b/src/Skia/Perspex.Skia.Android.TestApp/Resources/drawable/Icon.png differ
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/Resources/layout/Main.axml b/src/Skia/Perspex.Skia.Android.TestApp/Resources/layout/Main.axml
new file mode 100644
index 0000000000..98be1643ef
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android.TestApp/Resources/layout/Main.axml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/src/Skia/Perspex.Skia.Android.TestApp/Resources/values/Strings.xml b/src/Skia/Perspex.Skia.Android.TestApp/Resources/values/Strings.xml
new file mode 100644
index 0000000000..b410746644
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android.TestApp/Resources/values/Strings.xml
@@ -0,0 +1,5 @@
+
+
+ Hello World, Click Me!
+ Perspex.Skia.Android.TestApp
+
diff --git a/src/Skia/Perspex.Skia.Android/MethodTable.cs b/src/Skia/Perspex.Skia.Android/MethodTable.cs
new file mode 100644
index 0000000000..0e9d53ac14
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android/MethodTable.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+using Android.App;
+using Android.Content;
+using Android.Graphics;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+
+namespace Perspex.Skia
+{
+ class MethodTableImpl : MethodTable
+ {
+ [DllImport(@"perspesk")]
+ private static extern IntPtr GetPerspexMethodTable();
+ [DllImport(@"perspesk")]
+ private static extern IntPtr PerspexJniInit(IntPtr jniEnv);
+
+ public MethodTableImpl() : base(GetPerspexMethodTable())
+ {
+ PerspexJniInit(JNIEnv.Handle);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj b/src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj
new file mode 100644
index 0000000000..159d42584b
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj
@@ -0,0 +1,106 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ Perspex.Skia.Android
+ Perspex.Skia.Android
+ 512
+ Resources\Resource.Designer.cs
+ Off
+ True
+ v5.0
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {d211e587-d8bc-45b9-95a4-f297c8fa5200}
+ Perspex.Animation
+
+
+ {b09b78d8-9b26-48b0-9149-d64a2f120f3f}
+ Perspex.Base
+
+
+ {d2221c82-4a25-4583-9b43-d791e3f6820c}
+ Perspex.Controls
+
+
+ {62024b2d-53eb-4638-b26b-85eeaa54866e}
+ Perspex.Input
+
+
+ {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}
+ Perspex.Interactivity
+
+
+ {42472427-4774-4c81-8aff-9f27b8e31721}
+ Perspex.Layout
+
+
+ {eb582467-6abb-43a1-b052-e981ba910e3a}
+ Perspex.SceneGraph
+
+
+ {f1baa01a-f176-4c6a-b39d-5b40bb1b148f}
+ Perspex.Styling
+
+
+
+
+
+
+
+
+ native\armeabi-v7a\libperspesk.so
+
+
+ native\x86\libperspesk.so
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Skia/Perspex.Skia.Android/Resources/Resource.Designer.cs b/src/Skia/Perspex.Skia.Android/Resources/Resource.Designer.cs
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/Skia/Perspex.Skia.Android/SkiaView.cs b/src/Skia/Perspex.Skia.Android/SkiaView.cs
new file mode 100644
index 0000000000..934d282e2b
--- /dev/null
+++ b/src/Skia/Perspex.Skia.Android/SkiaView.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Android.App;
+using Android.Content;
+using Android.Graphics;
+using Android.OS;
+using Android.Runtime;
+using Android.Util;
+using Android.Views;
+using Android.Widget;
+using Perspex.Media;
+using Perspex.Platform;
+
+namespace Perspex.Skia.Android
+{
+ public abstract class SkiaView : SurfaceView, ISurfaceHolderCallback
+ {
+ private readonly Activity _context;
+ bool _invalidateQueued;
+ object _lock = new object();
+ public SkiaView(Activity context) : base(context)
+ {
+ _context = context;
+ SkiaPlatform.Initialize();
+ Holder.AddCallback(this);
+ }
+ private IRenderTarget _renderTarget;
+
+ public override void Invalidate()
+ {
+ lock (_lock)
+ {
+ if(_invalidateQueued)
+ return;
+ _context.RunOnUiThread(() =>
+ {
+ lock (_lock)
+ {
+ _invalidateQueued = false;
+ }
+ Draw();
+ });
+ }
+ }
+
+ public override void Invalidate(global::Android.Graphics.Rect dirty)
+ {
+ Invalidate();
+ }
+
+ public override void Invalidate(int l, int t, int r, int b)
+ {
+ Invalidate();
+ }
+
+ public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
+ {
+ Log.Info("PERSPEX", "Surface Changed");
+ _renderTarget.Resize(width, height);
+ Draw();
+ }
+
+ public void SurfaceCreated(ISurfaceHolder holder)
+ {
+ Log.Info("PERSPEX", "Surface Created");
+ _renderTarget =
+ PerspexLocator.Current.GetService()
+ .CreateRenderer(new PlatformHandle(holder.Surface.Handle, "Surface"), Width, Height);
+ Draw();
+ }
+
+ public void SurfaceDestroyed(ISurfaceHolder holder)
+ {
+ Log.Info("PERSPEX", "Surface Destroyed");
+ _renderTarget.Dispose();
+ _renderTarget = null;
+ }
+
+ void Draw()
+ {
+ if(_renderTarget == null)
+ return;
+ using (var ctx = _renderTarget.CreateDrawingContext())
+ OnRender(ctx);
+ }
+
+ protected abstract void OnRender(DrawingContext ctx);
+ }
+}
\ No newline at end of file