diff --git a/Perspex.sln b/Perspex.sln index 5f5e82fca7..1ddd288c70 100644 --- a/Perspex.sln +++ b/Perspex.sln @@ -123,6 +123,7 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.iOS", "src\Skia\Perspex.Skia.iOS\Perspex.Skia.iOS.csproj", "{47BE08A7-5985-410B-9FFC-2264B8EA595F}" EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestApplicationShared", "samples\TestApplicationShared\TestApplicationShared.shproj", "{78345174-5B52-4A14-B9FD-D5F2428137F0}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Android", "src\Android\Perspex.Android\Perspex.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}" @@ -136,17 +137,18 @@ Global 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\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\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4 samples\TestApplicationShared\TestApplicationShared.projitems*{78345174-5b52-4a14-b9fd-d5f2428137f0}*SharedItemsImports = 13 src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4 + samples\TestApplicationShared\TestApplicationShared.projitems*{ff69b927-c545-49ae-8e16-3d14d621aa12}*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*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4 src\Skia\Perspex.Skia\Perspex.Skia.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4 samples\TestApplicationShared\TestApplicationShared.projitems*{e3a1060b-50d0-44e8-88b6-f44ef2e5bd72}*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*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4 src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1157,16 +1159,36 @@ Global {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhone.Build.0 = Release|Any CPU {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.Build.0 = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhone.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Build.0 = Release|Any CPU {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Deploy.0 = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhone.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/TestApplicationShared/MainWindow.cs b/samples/TestApplicationShared/MainWindow.cs index 5df09b0d03..6a412a95b5 100644 --- a/samples/TestApplicationShared/MainWindow.cs +++ b/samples/TestApplicationShared/MainWindow.cs @@ -77,45 +77,30 @@ namespace TestApplication TabControl container; + Window window = new Window { Title = "Perspex Test Application", - Width = 900, - Height = 480, - Content = new Grid + //Width = 900, + //Height = 480, + Content = (container = new TabControl { - ColumnDefinitions = new ColumnDefinitions - { - new ColumnDefinition(1, GridUnitType.Star), - new ColumnDefinition(1, GridUnitType.Star), - }, - RowDefinitions = new RowDefinitions + Padding = new Thickness(5), + Items = new[] { - new RowDefinition(GridLength.Auto), - new RowDefinition(1, GridUnitType.Star), - new RowDefinition(GridLength.Auto), + ButtonsTab(), + TextTab(), + HtmlTab(), + ImagesTab(), + ListsTab(), + LayoutTab(), + AnimationsTab(), }, - Children = new Controls - { - (container = new TabControl - { - Padding = new Thickness(5), - Items = new[] - { - ButtonsTab(), - TextTab(), - HtmlTab(), - ImagesTab(), - ListsTab(), - LayoutTab(), - AnimationsTab(), - }, - Transition = new CrossFade(TimeSpan.FromSeconds(0.25)), - [Grid.RowProperty] = 1, - [Grid.ColumnSpanProperty] = 2, - }) - } - }, + Transition = new CrossFade(TimeSpan.FromSeconds(0.25)), + [Grid.RowProperty] = 1, + [Grid.ColumnSpanProperty] = 2, + }) + }; container.Classes.Add(":container"); diff --git a/src/Android/Perspex.Android/AndroidAssetLoader.cs b/src/Android/Perspex.Android/AndroidAssetLoader.cs deleted file mode 100644 index f10d0a8571..0000000000 --- a/src/Android/Perspex.Android/AndroidAssetLoader.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Android.Platform.Specific; -using Perspex.Platform; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; - -namespace Perspex.Android.PlatformSupport -{ - /// - /// Loads assets compiled into the application binary. - /// - public class AndroidAssetLoader : IAssetLoader - { - internal Assembly DefaultAssetAssembly { get; set; } - internal string DefaultResourcePrefix { get; set; } - - public AndroidAssetLoader() - { - //Assembly.GetEntryAssembly() not working on mono/xamarin for android!!! - //may be this is better way to have at least the application assembly as default one - DefaultAssetAssembly = PerspexLocator.Current.GetService().Activity.GetType().Assembly; - } - - private static readonly Dictionary AssemblyNameCache = new Dictionary(); - - /// - /// Checks if an asset with the specified URI exists. - /// - /// The URI. - /// True if the asset could be found; otherwise false. - public bool Exists(Uri uri) - { - return OpenInternal(uri, false) != null; - } - - /// - /// Opens the resource with the requested URI. - /// - /// The URI. - /// A stream containing the resource contents. - /// - /// The resource was not found. - /// - public Stream Open(Uri uri) - { - return OpenInternal(uri, true); - } - - private Stream OpenInternal(Uri uri, bool throwIfNotSuccess) - { - //uri.AbsolutePath is NotFiniteNumberException escaped adn can cause problems in assembly names with spaces - bool isAbsolute = uri.IsAbsoluteUri; - var parts = (isAbsolute ? uri.LocalPath : uri.OriginalString).Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - var asm = parts.Length == 1 ? DefaultAssetAssembly : GetAssembly(parts[0]); - var typeName = parts[parts.Length == 1 ? 0 : 1]; - if (typeName != null && !isAbsolute && !typeName.StartsWith(DefaultResourcePrefix)) - { - typeName = DefaultResourcePrefix + typeName; - } - - var rv = asm.GetManifestResourceStream(typeName); - if (rv == null && throwIfNotSuccess) - throw new FileNotFoundException($"The resource {uri} could not be found."); - return rv; - } - - private static Assembly GetAssembly(string name) - { - Assembly rv; - if (!AssemblyNameCache.TryGetValue(name, out rv)) - AssemblyNameCache[name] = rv = - AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == name) - ?? Assembly.Load(name); - return rv; - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/AndroidPlatform.cs b/src/Android/Perspex.Android/AndroidPlatform.cs index 6e6b061d8c..feb4288c8c 100644 --- a/src/Android/Perspex.Android/AndroidPlatform.cs +++ b/src/Android/Perspex.Android/AndroidPlatform.cs @@ -1,11 +1,7 @@ -using Android.OS; using Perspex.Android.CanvasRendering; using Perspex.Android.Platform; using Perspex.Android.Platform.Input; using Perspex.Android.Platform.Specific; -using Perspex.Android.Platform.Specific.Helpers; -using Perspex.Android.PlatformSupport; -using Perspex.Animation; using Perspex.Controls.Platform; using Perspex.Input; using Perspex.Input.Platform; @@ -14,228 +10,44 @@ using Perspex.Shared.PlatformSupport; using Perspex.Skia; using System; using System.Collections.Generic; -using System.Reactive.Disposables; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; namespace Perspex.Android { - public class AndroidPlatform : IPlatformThreadingInterface, IPlatformSettings + public class AndroidPlatform : IPlatformSettings { public static readonly AndroidPlatform Instance = new AndroidPlatform(); public Size DoubleClickSize => new Size(4, 4); public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(200); - - private HashSet _renderingTask = new HashSet(); - - public void RegisterRenderingTaskId(int taskId) - { - _renderingTask.Add(taskId); - } - - public void UnRegisterRenderingTaskId(int taskId) - { - _renderingTask.Add(taskId); - } - - public bool CurrentThreadIsLoopThread - { - get - { - bool res = Looper.MainLooper.Thread.Equals(Java.Lang.Thread.CurrentThread()); - if (!res) - { - if (Task.CurrentId != null) - { - int id = Task.CurrentId.Value; - res = _renderingTask.Contains(Task.CurrentId.Value); - } - } - - return res; - } - } - - public void RunLoop(CancellationToken cancellationToken) - { - } - - private TimeSpan _animationTick = TimeSpan.FromSeconds(1.0 / Animate.FramesPerSecond); - - public IDisposable StartTimer(TimeSpan interval, Action tick) - { - //we should be carefull about the smallest amount of time the timer ticks - //as on android for animations so far there is some issue with 60 fps - //for now we can get set it to 16 fps with observable timer - //and still random native exceptions causing app to stop!!!! - //better not use it - //return Observable.Timer(interval, interval).Subscribe(_ => tick()); - - //System.Threading.Timer - //int ms = (int)interval.TotalMilliseconds; - ////regular timer is working perfect - //return new System.Threading.Timer(_ => tick(), null, ms, ms); - - //when interval is 0 normal System.Timers.Timer is not working - //so we ween other strategy for that - if (interval.TotalMilliseconds == 0) - { - if(DefaultViewDrawType == ViewDrawType.Skia) - { - //or start timer with low enough interval 10ms ??? - //with skia when animation active if we use RunOnUiThread UI is not handling the events!!! issue or not? - interval = TimeSpan.FromMilliseconds(10); - } - else - { - //android ui thread - PerspexLocator.Current.GetService().Activity.RunOnUiThread(tick); - return Disposable.Empty; - } - } - else if (OverrideAnimateFramesPerSecond > 0) - { - if (_animationTick >= interval) - { - interval = TimeSpan.FromSeconds(1.0 / OverrideAnimateFramesPerSecond); - } - } - - //working not very bad with standard timer - //var timer = new System.Timers.Timer(interval.TotalMilliseconds); - //System.Timers.ElapsedEventHandler elapsed = (s, e) => tick(); - //timer.Elapsed += elapsed; - //timer.Start(); - //return Disposable.Create(() => - //{ - // timer.Stop(); - // timer.Elapsed -= elapsed; - // timer.Dispose(); - //}); - - //common ui timer is optimizing performance - //a lot almost twice, also may be processor usage - //most probably because it optimizes invalidation calls in animations and using less system resources - CommonUITimer timer; - if (!_commonTimers.TryGetValue(interval, out timer)) - { - timer = new CommonUITimer(interval); - _commonTimers.Add(interval, timer); - } - - timer.AddAction(tick); - - return Disposable.Create(() => - { - timer.RemoveAction(tick); - - if (timer.ActiveActionsCount == 0) - { - timer.Dispose(); - _commonTimers.Remove(interval); - } - }); - } - - private Dictionary _commonTimers = new Dictionary(); - - public void Signal() - { - EnsureInvokeOnMainThread(() => Signaled?.Invoke()); - } - - public event Action Signaled; - - public static void Initialize() + + AndroidPlatform() { + var settings = new PlatformSettings(); PerspexLocator.CurrentMutable .Bind().ToTransient() .Bind().ToTransient() .Bind().ToSingleton() .Bind().ToSingleton() - .Bind().ToConstant(Instance) - .Bind().ToConstant(Instance) + .Bind().ToConstant(this) + .Bind().ToConstant(new AndroidThreadingInterface()) .Bind().ToTransient() - .Bind().ToSingleton() .Bind().ToTransient() - .Bind().ToConstant(new PlatformSettings()); - ; - - Instance.RegisterViewDrawType(); - //set defaults for simple resources - //Assembly.GetEntryAssembly(); //not working on mono for android - var appType = Application.Current.GetType(); - var entryAssembly = appType.Assembly; - AndroidPlatform.Instance.InitializeAssetsLoader(entryAssembly, appType.Namespace + "."); - // SharedPlatform.Register(); - //we have custom Assetloader so no need to overwrite it - PerspexLocator.CurrentMutable - .Bind().ToSingleton(); - } - - public void RegisterViewDrawType() - { - if (Instance.DefaultViewDrawType == ViewDrawType.Skia) - { - //do the default initialization for skia rendering - SkiaPlatform.Initialize(); - PerspexLocator.CurrentMutable.Bind().ToSingleton(); - } - else - { - AndroidPlatformRender.Initialize(); - - if (Instance.DefaultViewDrawType == ViewDrawType.SurfaceViewCanvasOnDraw) - { - PerspexLocator.CurrentMutable.Bind().ToSingleton(); - } - else - { - PerspexLocator.CurrentMutable.Bind().ToSingleton(); - } - - PerspexLocator.CurrentMutable.Bind().ToTransient(); - } - } + .Bind().ToConstant(settings); - public void RegisterViewPointUnits() - { - PerspexLocator.CurrentMutable.Bind().ToSingleton(); - } + SkiaPlatform.Initialize(); + Application.SuppressPlatformInitialization(); + PerspexLocator.CurrentMutable.Bind().ToSingleton(); - public void InitializeAssetsLoader(Assembly assembly, string defaultResourcePrefix) - { - var assetLoder = PerspexLocator.Current.GetService() as AndroidAssetLoader; - if (assetLoder != null) - { - assetLoder.DefaultAssetAssembly = assembly; - assetLoder.DefaultResourcePrefix = defaultResourcePrefix; - } + var scale = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity; + PerspexLocator.Current.GetService().LayoutScalingFactor = scale; + PerspexLocator.Current.GetService().RenderScalingFactor = scale; + + //we have custom Assetloader so no need to overwrite it + } - private void EnsureInvokeOnMainThread(Action action) + public void Init(Type applicationType) { - var mainHandler = new Handler(global::Android.App.Application.Context.MainLooper); - mainHandler.Post(action); + SharedPlatform.Register(applicationType.Assembly); } - - public bool DrawDebugInfo { get; set; } = false; - - /// - /// Default View DrawType - /// WindowImpl supports: - /// ViewDrawType.CanvasOnDraw - /// ViewDrawType.BitmapOnPreDraw - /// BitmapBackgroundRender - /// by default it is ViewDrawType.CanvasOnDraw simples way of drawing view - /// SurfaceWindowImpl supports: - /// SurfaceViewCanvasOnDraw - /// - public ViewDrawType DefaultViewDrawType { get; set; } = ViewDrawType.Skia; - - public Platform.CanvasPlatform.PointUnit DefaultPointUnit { get; set; } = Platform.CanvasPlatform.PointUnit.DP; - - public int OverrideAnimateFramesPerSecond { get; set; } = -1; } } \ No newline at end of file diff --git a/src/Android/Perspex.Android/AndroidThreadingInterface.cs b/src/Android/Perspex.Android/AndroidThreadingInterface.cs new file mode 100644 index 0000000000..072b507b79 --- /dev/null +++ b/src/Android/Perspex.Android/AndroidThreadingInterface.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reactive.Disposables; +using System.Text; +using System.Threading; +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Perspex.Platform; + +namespace Perspex.Android +{ + class AndroidThreadingInterface : IPlatformThreadingInterface + { + private Handler _handler; + + public AndroidThreadingInterface() + { + _handler = new Handler(global::Android.App.Application.Context.MainLooper); + } + + public void RunLoop(CancellationToken cancellationToken) + { + return; + } + + public IDisposable StartTimer(TimeSpan interval, Action tick) + { + if (interval.TotalMilliseconds < 10) + interval = TimeSpan.FromMilliseconds(10); + object l = new object(); + var stopped = false; + Timer timer = null; + var scheduled = false; + timer = new Timer(_ => + { + lock (l) + { + if (stopped) + { + timer.Dispose(); + return; + } + if (scheduled) + return; + scheduled = true; + EnsureInvokeOnMainThread(() => + { + tick(); + lock (l) + { + scheduled = false; + } + }); + } + }, null, TimeSpan.Zero, interval); + + return Disposable.Create(() => + { + lock (l) + { + stopped = true; + timer.Dispose(); + } + }); + } + + private void EnsureInvokeOnMainThread(Action action) => _handler.Post(action); + + public void Signal() + { + EnsureInvokeOnMainThread(() => Signaled?.Invoke()); + } + + public bool CurrentThreadIsLoopThread => Looper.MainLooper.Thread.Equals(Java.Lang.Thread.CurrentThread()); + public event Action Signaled; + } +} + \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/AndroidGraphicsExtensions.cs b/src/Android/Perspex.Android/CanvasRendering/AndroidGraphicsExtensions.cs deleted file mode 100644 index 2ee877352a..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/AndroidGraphicsExtensions.cs +++ /dev/null @@ -1,246 +0,0 @@ -using Perspex.Android.Platform.CanvasPlatform; -using Perspex.Android.Platform.Specific; -using Perspex.Media; -using System; -using AAllignment = Android.Text.Layout.Alignment; -using ACap = Android.Graphics.Paint.Cap; -using AColor = Android.Graphics.Color; -using AJoin = Android.Graphics.Paint.Join; -using AMatrix = Android.Graphics.Matrix; -using APoint = Android.Graphics.PointF; -using ARect = Android.Graphics.Rect; -using ARectF = Android.Graphics.RectF; -using AStyle = Android.Graphics.Paint.Style; -using ATextAlign = Android.Graphics.Paint.Align; -using ATileMode = Android.Graphics.Shader.TileMode; -using ATypeface = Android.Graphics.Typeface; -using ATypeStyle = Android.Graphics.TypefaceStyle; - -namespace Perspex.Android.CanvasRendering -{ - public static class AndroidGraphicsExtensions - { - public static AColor ToAndroidGraphics(this Color c) - { - return new AColor(c.R, c.G, c.B, c.A); - } - - public static AMatrix ToAndroidGraphics(this Matrix matrix) - { - var ps = PointUnitService.Instance; - //TODO: !!! - var transformValues = new float[9]; - transformValues[0] = (float)matrix.M11; - transformValues[1] = (float)matrix.M21; - transformValues[2] = ps.PerspexToNativeXF(matrix.M31); - //transformValues[2] = (float)matrix.M31; - - transformValues[3] = (float)matrix.M12; - transformValues[4] = (float)matrix.M22; - transformValues[5] = ps.PerspexToNativeYF(matrix.M32); - //transformValues[5] = (float)matrix.M32; - - transformValues[6] = 0; - transformValues[7] = 0; - transformValues[8] = 1; - var am = new AMatrix(); - am.SetValues(transformValues); - return am; - } - - //public static Matrix ToPerspex(this AMatrix m) - //{ - // var v = new float[9]; - // m.GetValues(v); - // return new Matrix(v[0], v[3], v[1], v[4], v[2], v[5]); - //} - - public static APoint ToAndroidGraphics(this Point p, bool notransform = false) - { - if (notransform) new APoint((float)p.X, (float)p.Y); - var ps = PointUnitService.Instance; - return new APoint(ps.PerspexToNativeXF(p.X), ps.PerspexToNativeYF(p.Y)); - } - - //public static Point ToPerspex(this APoint p) - //{ - // return new Point(p.X, p.Y); - //} - - public static ARect ToAndroidGraphics(this Rect r, bool notransform = false) - { - if (notransform) return new ARect((int)r.X, (int)r.Y, (int)r.Right, (int)r.Bottom); - var ps = PointUnitService.Instance; - return new ARect(ps.PerspexToNativeXInt(r.X), ps.PerspexToNativeYInt(r.Y), ps.PerspexToNativeXInt(r.Right), ps.PerspexToNativeYInt(r.Bottom)); - } - - public static ARectF ToAndroidGraphicsF(this Rect r) - { - var ps = PointUnitService.Instance; - return new ARectF(ps.PerspexToNativeXF(r.X), ps.PerspexToNativeYF(r.Y), ps.PerspexToNativeXF(r.Right), ps.PerspexToNativeYF(r.Bottom)); - } - - //public static Rect ToPerspex(this ARect r) - //{ - // return new Rect(r.Left, r.Top, r.Width(), r.Height()); - //} - - public static Rect ToPerspex(this ARectF r) - { - var ps = PointUnitService.Instance; - return new Rect(ps.NativeToPerspexX(r.Left), ps.NativeToPerspexY(r.Top), ps.NativeToPerspexX(r.Width()), ps.NativeToPerspexY(r.Height())); - } - - public static AJoin ToAndroidGraphics(this PenLineJoin plj) - { - switch (plj) - { - default: - case PenLineJoin.Bevel: - return AJoin.Bevel; - - case PenLineJoin.Miter: - return AJoin.Miter; - - case PenLineJoin.Round: - return AJoin.Round; - } - } - - public static ACap ToAndroidGraphics(this PenLineCap plc) - { - switch (plc) - { - default: - case PenLineCap.Flat: - return ACap.Butt; - - case PenLineCap.Round: - return ACap.Round; - - case PenLineCap.Square: - return ACap.Square; - //Triangle not supported - case PenLineCap.Triangle: - goto default; - } - } - - public static AStyle ToAndroidGraphics(this BrushUsage bu) - { - switch (bu) - { - default: - case BrushUsage.Fill: - return AStyle.Fill; - - case BrushUsage.Stroke: - return AStyle.Stroke; - - case BrushUsage.Both: - return AStyle.FillAndStroke; - } - } - - public static ATypeface ToAndroidGraphicsTypeface(this FontStyle s, FontWeight fontWeight) - { - ATypeface result = ATypeface.Default; - - if (fontWeight >= FontWeight.Bold) - { - result = ATypeface.DefaultBold; - } - - return result; - } - - public static ATypeStyle ToAndroidGraphicsTypefaceStyle(this FontStyle s, FontWeight fontWeight) - { - ATypeStyle result; - switch (s) - { - default: - case FontStyle.Normal: - result = ATypeStyle.Normal; - break; - - case FontStyle.Italic: - result = ATypeStyle.Italic; - break; - //Oblique not supported, return normal - case FontStyle.Oblique: - goto default; - } - - if (fontWeight >= FontWeight.Bold) - { - result = result == ATypeStyle.Italic ? ATypeStyle.BoldItalic : ATypeStyle.Bold; - } - - return result; - } - - public static ATextAlign ToAndroidGraphics(this TextAlignment ta) - { - switch (ta) - { - default: - case TextAlignment.Left: - return ATextAlign.Left; - - case TextAlignment.Center: - return ATextAlign.Center; - - case TextAlignment.Right: - return ATextAlign.Right; - } - } - - public static AAllignment ToAndroidGraphicsLayoutAligment(this TextAlignment ta) - { - switch (ta) - { - default: - case TextAlignment.Left: - return AAllignment.AlignNormal; - - case TextAlignment.Center: - return AAllignment.AlignCenter; - - case TextAlignment.Right: - return AAllignment.AlignOpposite; - } - } - - public static ATileMode ToAndroidGraphicsX(this TileMode tileMode) - { - switch (tileMode) - { - case TileMode.Tile: return ATileMode.Repeat; - case TileMode.FlipX: return ATileMode.Mirror; - case TileMode.FlipXY: return ATileMode.Mirror; - case TileMode.FlipY: return ATileMode.Clamp; - case TileMode.None: return ATileMode.Clamp; - default: return ATileMode.Clamp; - } - } - - public static ATileMode ToAndroidGraphicsY(this TileMode tileMode) - { - switch (tileMode) - { - case TileMode.Tile: return ATileMode.Repeat; - case TileMode.FlipX: return ATileMode.Clamp; - case TileMode.FlipXY: return ATileMode.Mirror; - case TileMode.FlipY: return ATileMode.Mirror; - case TileMode.None: return ATileMode.Clamp; - default: return ATileMode.Clamp; - } - } - - public static int OpacityToAndroidAlfa(double opacity) - { - return Convert.ToInt32(opacity * 255); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/AndroidPlatformRender.cs b/src/Android/Perspex.Android/CanvasRendering/AndroidPlatformRender.cs deleted file mode 100644 index bab5a6a287..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/AndroidPlatformRender.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Perspex.Android.Platform.Specific; -using Perspex.Media; -using Perspex.Platform; -using System.IO; -using AG = Android.Graphics; -using System; -using Perspex.Android.Platform.CanvasPlatform; - -namespace Perspex.Android.CanvasRendering -{ - public class AndroidPlatformRender : IPlatformRenderInterface - { - private static readonly AndroidPlatformRender instance = new AndroidPlatformRender(); - - public IFormattedTextImpl CreateFormattedText(string text, string fontFamilyName, double fontSize, - FontStyle fontStyle, - TextAlignment textAlignment, FontWeight fontWeight) - { - return new FormattedTextImpl(text, fontFamilyName, fontSize, fontStyle, textAlignment, fontWeight); - } - - public IStreamGeometryImpl CreateStreamGeometry() - { - return new StreamGeometryImpl(); - } - - public IRenderTarget CreateRenderer(IPlatformHandle handle) - { - return new RenderTarget((IAndroidCanvasView)handle); - } - - public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int pwidth, int pheight) - { - int width = PointUnitService.Instance.PerspexToNativeXInt(pwidth); - int height = PointUnitService.Instance.PerspexToNativeYInt(pwidth); - - return new RenderTargetBitmapImpl(CreateNativeBitmap(width, height)); - } - - public IBitmapImpl CreateBitmap(int pwidth, int pheight) - { - int width = PointUnitService.Instance.PerspexToNativeXInt(pwidth); - int height = PointUnitService.Instance.PerspexToNativeYInt(pwidth); - return new BitmapImpl(CreateNativeBitmap(width, height)); - } - - public IBitmapImpl LoadBitmap(string fileName) - { - return new BitmapImpl(AG.BitmapFactory.DecodeFile(fileName)); - } - - public IBitmapImpl LoadBitmap(Stream stream) - { - return new BitmapImpl(AG.BitmapFactory.DecodeStream(stream)); - } - - public static void Initialize() - => PerspexLocator.CurrentMutable.Bind().ToConstant(instance); - - private AG.Bitmap CreateNativeBitmap(int width, int height) - { - return AG.Bitmap.CreateBitmap(width, height, AG.Bitmap.Config.Argb8888); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/BitmapImpl.cs b/src/Android/Perspex.Android/CanvasRendering/BitmapImpl.cs deleted file mode 100644 index d34d5aa59a..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/BitmapImpl.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Platform; -using System.IO; -using AG = Android.Graphics; - -namespace Perspex.Android.CanvasRendering -{ - public class BitmapImpl : IBitmapImpl - { - public BitmapImpl(AG.Bitmap bitmap) - { - PlatformBitmap = bitmap; - } - - public int PixelWidth => PlatformBitmap.Width; - - public int PixelHeight => PlatformBitmap.Height; - - public AG.Bitmap PlatformBitmap - { - get; - } - - public void Save(string fileName) - { - using (var f = File.OpenWrite(fileName)) - { - PlatformBitmap.Compress(AG.Bitmap.CompressFormat.Png, 100, f); - } - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/BrushImpl.cs b/src/Android/Perspex.Android/CanvasRendering/BrushImpl.cs deleted file mode 100644 index 7ddc3610d7..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/BrushImpl.cs +++ /dev/null @@ -1,363 +0,0 @@ -using Android.Graphics; -using Android.Util; -using Perspex.Android.Platform.CanvasPlatform; -using Perspex.Android.Platform.Specific; -using Perspex.Media; -using System; -using System.Collections.Generic; -using System.Linq; -using AColor = Android.Graphics.Color; - -namespace Perspex.Android.CanvasRendering -{ - public enum BrushUsage - { - Fill, - Stroke, - Both - }; - - public interface INativePaintWrapper : IDisposable - { - Paint NativePaint { get; } - - void PushOpacity(double value); - - void PopOpacity(); - } - - public abstract class BrushImpl : IDisposable, INativePaintWrapper - { - public BrushImpl(Brush brush) - { - Brush = brush; - Brush.PropertyChanged += Brush_PropertyChanged; - Init(); - } - - protected virtual void Init() - { - Opacity = Brush.Opacity; - } - - private void Brush_PropertyChanged(object sender, PerspexPropertyChangedEventArgs e) - { - _isDirty = true; - } - - protected bool _isDirty = false; - - public Brush Brush { get; private set; } - - private double _oldOpacity = 1; - - public double Opacity { get; private set; } - - public virtual void Dispose() - { - Brush.PropertyChanged -= Brush_PropertyChanged; - Brush = null; - NativePaint?.Dispose(); - } - - private Paint _nativeBrush; - - public Paint NativePaint - { - get - { - if (_nativeBrush == null) - { - _nativeBrush = new Paint(PaintFlags.AntiAlias); - _isDirty = true; - } - - if (_isDirty) - { - Apply(); - } - - return _nativeBrush; - } - } - - public Paint.Style Style { get; set; } - - public virtual void ApplyTo(Paint paint) - { - paint.Alpha = AndroidGraphicsExtensions.OpacityToAndroidAlfa(Opacity); - paint.SetStyle(Style); - } - - private void Apply() - { - _isDirty = false; - ApplyTo(NativePaint); - } - - private static readonly BrushImpl FallbackBrush = new SolidColorBrushImpl(new SolidColorBrush(Colors.Transparent)); - - public static BrushImpl Create(Brush brush, Size dstRect, Paint.Style style) - { - //Size dstRect = PointService.Instance.PerspexToNative(pdstRect); - BrushImpl impl = null; - - if (brush is SolidColorBrush) - { - impl = new SolidColorBrushImpl(brush as SolidColorBrush); - } - else if (brush is LinearGradientBrush) - { - impl = new LinearGradientBrushImpl(brush as LinearGradientBrush, dstRect); - } - else if (brush is RadialGradientBrush) - { - impl = new RadialGradientBrushImpl(brush as RadialGradientBrush, dstRect); - } - else if (brush is ImageBrush) - { - impl = new ImageBrushImpl(brush as ImageBrush); - } - else if (brush is VisualBrush) - { - // TODO: Implement me - Log.Debug("REND", "VisualBrush not implemented"); - impl = FallbackBrush; - } - else - { - impl = new SolidColorBrushImpl(null); - } - - impl.Style = style; - - return impl; - } - - private Stack _opacityStack = new Stack(); - - public void PushOpacity(double value) - { - _opacityStack.Push(this.Opacity); - Opacity = Opacity * value; - _isDirty = value != 1 ? true : false; - } - - public void PopOpacity() - { - double newOpacity = _opacityStack.Pop(); - if (newOpacity != Opacity) - { - Opacity = newOpacity; - _isDirty = true; - } - } - } - - public class PenImpl : IDisposable, INativePaintWrapper - { - public PenImpl(Pen pen, Size dstRect, Paint.Style style) - { - this.Pen = pen; - if (this.Pen.Brush != null) - { - this.Brush = BrushImpl.Create(this.Pen.Brush, dstRect, style); - } - } - - private BrushImpl Brush { get; set; } - - public Pen Pen { get; } - - private Paint _nativePaint; - - public Paint NativePaint - { - get - { - if (_nativePaint == null) - { - _nativePaint = new Paint(PaintFlags.AntiAlias); - Apply(); - } - - return _nativePaint; - } - set - { - this._nativePaint = value; - } - } - - public void PushOpacity(double opacity) - { - Brush?.PushOpacity(opacity); - } - - public void PopOpacity() - { - Brush?.PopOpacity(); - } - - private void Apply() - { - if (Pen.DashStyle?.Dashes != null && Pen.DashStyle.Dashes.Count > 0) - { - var cray = Pen.DashStyle.Dashes.Select(d => (float)d).ToArray(); - NativePaint.SetPathEffect(new DashPathEffect(cray, (float)Pen.DashStyle.Offset)); - } - - NativePaint.StrokeWidth = PointUnitService.Instance.PerspexToNativeXF(Pen.Thickness); - NativePaint.StrokeMiter = (float)Pen.MiterLimit; - - NativePaint.StrokeJoin = Pen.LineJoin.ToAndroidGraphics(); - NativePaint.StrokeCap = Pen.StartLineCap.ToAndroidGraphics(); - - if (Brush != null) - { - Brush.ApplyTo(NativePaint); - } - } - - public void Dispose() - { - Brush?.Dispose(); - } - } - - public class SolidColorBrushImpl : BrushImpl - { - private AColor _nativeColor; - - public SolidColorBrushImpl(SolidColorBrush brush) : base(brush) - { - } - - public override void ApplyTo(Paint paint) - { - paint.Color = _nativeColor; - base.ApplyTo(paint); - } - - protected override void Init() - { - base.Init(); - var brush = Brush as SolidColorBrush; - - _nativeColor = brush.Color.ToAndroidGraphics(); - } - } - - public class ShaderBrushImpl : BrushImpl - { - protected Shader Shader { get; set; } - - protected Size DestinationSize { get; } - - public ShaderBrushImpl(Brush brush, Size destinationSize) : base(brush) - { - DestinationSize = destinationSize; - } - - public override void ApplyTo(Paint paint) - { - base.ApplyTo(paint); - - if (Shader != null) - { - paint.SetShader(Shader); - } - else - { - //we had some problem better set something - paint.Color = new AColor(0, 0, 0, 255); - } - } - - public override void Dispose() - { - Shader?.Dispose(); - base.Dispose(); - } - } - - public class LinearGradientBrushImpl : ShaderBrushImpl - { - public LinearGradientBrushImpl(LinearGradientBrush brush, Size destinationSize) : base(brush, destinationSize) - { - } - - protected override void Init() - { - base.Init(); - var brush = Brush as LinearGradientBrush; - int n = brush.GradientStops.Count; - var offsets = new float[n]; - var colors = new int[n]; - for (var i = 0; i < n; i++) - { - var s = brush.GradientStops[i]; - offsets[i] = (float)s.Offset; - colors[i] = (int)s.Color.ToUint32(); - } - - var startPoint = brush.StartPoint.ToPixels(DestinationSize); - var endPoint = brush.EndPoint.ToPixels(DestinationSize); - - this.Shader = new LinearGradient( - (float)startPoint.X, (float)startPoint.Y, - (float)endPoint.X, (float)endPoint.Y, - colors, - offsets, - Shader.TileMode.Clamp); - } - } - - public class RadialGradientBrushImpl : ShaderBrushImpl - { - public RadialGradientBrushImpl(RadialGradientBrush brush, Size destinationSize) : base(brush, destinationSize) - { - } - - protected override void Init() - { - base.Init(); - var brush = Brush as RadialGradientBrush; - int n = brush.GradientStops.Count; - var offsets = new float[n]; - var colors = new int[n]; - - for (var i = 0; i < n; i++) - { - var s = brush.GradientStops[i]; - offsets[i] = (float)s.Offset; - colors[i] = (int)s.Color.ToUint32(); - } - - var centerPoint = brush.Center.ToPixels(DestinationSize); - double radius = brush.Center.Unit == RelativeUnit.Absolute ? brush.Radius : Math.Max(brush.Radius * DestinationSize.Width, brush.Radius * DestinationSize.Height); - - Shader = new RadialGradient( - (float)centerPoint.X, (float)centerPoint.Y, - (float)brush.Radius, - colors, - offsets, - Shader.TileMode.Clamp); - } - } - - public class ImageBrushImpl : ShaderBrushImpl - { - public ImageBrushImpl(ImageBrush brush) : base(brush, default(Size)) - { - } - - protected override void Init() - { - base.Init(); - var brush = Brush as ImageBrush; - var bmp = brush.Source.PlatformImpl as BitmapImpl; - Shader = new BitmapShader(bmp.PlatformBitmap, brush.TileMode.ToAndroidGraphicsX(), brush.TileMode.ToAndroidGraphicsY()); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/DrawingContext.cs b/src/Android/Perspex.Android/CanvasRendering/DrawingContext.cs deleted file mode 100644 index 522012d1d2..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/DrawingContext.cs +++ /dev/null @@ -1,248 +0,0 @@ -using Android.Graphics; -using Perspex.Android.Platform.CanvasPlatform; -using Perspex.Android.Platform.Specific; -using Perspex.Media; -using Perspex.Media.Imaging; -using System; -using System.Collections.Generic; -using System.Reactive.Disposables; - -namespace Perspex.Android.CanvasRendering -{ - public class DrawingContextImpl : IDrawingContextImpl - { - private double _currentOpacity = 1.0f; - - private double CurrentOpacity - { - get { return _currentOpacity; } - set - { - _currentOpacity = value; - } - } - - public Canvas _canvas; - private Dictionary _visualCaches; - private Dictionary _cache; - - public DrawingContextImpl(Canvas canvas, Dictionary visualCaches) - { - _canvas = canvas; - _visualCaches = visualCaches; - _cache = visualCaches ?? new Dictionary(); - } - - public void Dispose() - { - _canvas = null; - if (_visualCaches == null) - { - DisposeCaches(); - } - } - - private void DisposeCaches() - { - foreach (var d in _cache) - { - d.Value.Dispose(); - } - _cache.Clear(); - } - - private Matrix _currentTransform = Matrix.Identity; - - public Matrix Transform - { - get { return _currentTransform; } - set - { - if (_currentTransform == value) - return; - _currentTransform = value; - _canvas.Matrix = value.ToAndroidGraphics(); - } - } - - public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) - { - var nativeBitmap = (source.PlatformImpl as BitmapImpl).PlatformBitmap; - _canvas.DrawBitmap(nativeBitmap, sourceRect.ToAndroidGraphics(true), destRect.ToAndroidGraphicsF(), new Paint() { Alpha = AndroidGraphicsExtensions.OpacityToAndroidAlfa(opacity * CurrentOpacity) }); - } - - public void DrawLine(Pen pen, Point pp1, Point pp2) - { - var p1 = PointUnitService.Instance.PerspexToNative(pp1); - var p2 = PointUnitService.Instance.PerspexToNative(pp2); - - var Rect = new Rect(p1.X, p1.Y, p2.X, p2.Y); - PenImpl np; - using ((GetPen(pen, new Size(Rect.Width, Rect.Height), out np))) - { - _canvas.DrawLine((float)p1.X, (float)p1.Y, (float)p2.X, (float)p2.Y, np.NativePaint); - } - } - - public void DrawGeometry(Brush brush, Pen pen, Geometry geometry) - { - var impl = geometry.PlatformImpl as StreamGeometryImpl; - - if (brush != null) - { - BrushImpl nb; - using (var b = GetBrush(brush, geometry.Bounds.Size, out nb)) - { - _canvas.DrawPath(impl.Path, nb.NativePaint); - } - } - - //if the pen brush is null and thickness null on android - //the shape is filled with black !! better not draw the stroke!!! - if (pen?.Brush != null && pen?.Thickness > 0) - { - PenImpl np; - using (var p = GetPen(pen, geometry.Bounds.Size, out np)) - { - _canvas.DrawPath(impl.Path, np.NativePaint); - } - } - } - - public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0) - { - PenImpl np; - using (GetPen(pen, rect.Size, out np)) - { - if (cornerRadius == 0) - { - _canvas.DrawRect(rect.ToAndroidGraphicsF(), np.NativePaint); - } - else - { - _canvas.DrawRoundRect(rect.ToAndroidGraphicsF(), cornerRadius, cornerRadius, np.NativePaint); - } - } - } - - public void DrawText(Brush foreground, Point origin, FormattedText text) - { - if (!string.IsNullOrEmpty(text.Text)) - { - var ap = origin.ToAndroidGraphics(); - var impl = (FormattedTextImpl)text.PlatformImpl; - _canvas.Save(); - BrushImpl nb; - using (var b = GetBrush(foreground, impl.Measure(), out nb)) - { - nb.ApplyTo(impl.TextPaint); - _canvas.Translate((float)ap.X, (float)ap.Y); - impl.TextLayout.Draw(_canvas); - } - _canvas.Restore(); - } - } - - public void FillRectangle(Brush brush, Rect rect, float cornerRadius = 0) - { - BrushImpl np; - using (var b = GetBrush(brush, rect.Size, out np)) - { - var ar = rect.ToAndroidGraphicsF(); - if (cornerRadius == 0) - { - _canvas.DrawRect(ar, np.NativePaint); - } - else - { - var cr = PointUnitService.Instance.PerspexToNativeXF(cornerRadius); - _canvas.DrawRoundRect(ar, cr, cr, np.NativePaint); - //Canvas.DrawPath(RoundRectPath(rect, cornerRadius), nb.NativePaint); - } - } - } - - private Rect _clip; - - public void PushClip(Rect clip) - { - _canvas.Save(); - _canvas.ClipRect(clip.ToAndroidGraphics()); - _clip = clip; - } - - public void PopClip() => _canvas.Restore(); - - private Stack _opacityStack = new Stack(); - - public void PushOpacity(double opacity) - { - _opacityStack.Push(CurrentOpacity); - CurrentOpacity = CurrentOpacity * opacity; - } - - public void PopOpacity() => CurrentOpacity = _opacityStack.Pop(); - - //private Path RoundRectPath(Rect rc, float radius) - //{ - // var x = (float)rc.TopLeft.X; - // var y = (float)rc.TopLeft.Y; - // var width = (float)rc.Width; - // var height = (float)rc.Height; - // var rx = radius; - // var ry = radius; - // var path = new Path(); - // path.MoveTo(x + rx, y); - // path.LineTo(x + width - rx, y + 0); - // path.QuadTo(x + width, y, x + width, y + ry); - // path.LineTo(x + width, y + height - ry); - // path.QuadTo(x + width, y + height, x + width - rx, y + height); - // path.LineTo(x + rx, y + height); - // path.QuadTo(x, y + height, x, y + height - ry); - // path.LineTo(x, y + ry); - // path.QuadTo(x, y, x + rx, y); - // return path; - //} - - private IDisposable GetPen(Pen pen, Size dstRect, out PenImpl result) - { - var penImpl = GetOrCreatePaintWrapper(pen, () => new PenImpl(pen, dstRect, Paint.Style.Stroke)); - - penImpl.PushOpacity(CurrentOpacity); - - result = penImpl; - - return Disposable.Create(() => penImpl.PopOpacity()); - } - - private IDisposable GetBrush(Brush brush, Size dstRect, out BrushImpl result) - { - var brushImpl = GetOrCreatePaintWrapper(brush, () => BrushImpl.Create(brush, dstRect, Paint.Style.Fill)); - - brushImpl.PushOpacity(CurrentOpacity); - - result = brushImpl; - - return Disposable.Create(() => brushImpl.PopOpacity()); - } - - private T GetOrCreatePaintWrapper(object key, Func createFunc) where T : INativePaintWrapper - { - IDisposable cachedVisual; - T result; - - if (!_cache.TryGetValue(key, out cachedVisual)) - { - result = createFunc(); - - _cache[key] = result; - } - else - { - result = (T)cachedVisual; - } - - return result; - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/FormattedTextImpl.cs b/src/Android/Perspex.Android/CanvasRendering/FormattedTextImpl.cs deleted file mode 100644 index 621812709f..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/FormattedTextImpl.cs +++ /dev/null @@ -1,205 +0,0 @@ -using Android.Graphics; -using Android.Text; -using Perspex.Android.Platform.CanvasPlatform; -using Perspex.Android.Platform.Specific; -using Perspex.Media; -using Perspex.Platform; -using System; -using System.Collections.Generic; -using AAllignment = Android.Text.Layout.Alignment; -using ARect = Android.Graphics.Rect; -using ATextPaint = Android.Text.TextPaint; - -namespace Perspex.Android.CanvasRendering -{ - public class FormattedTextImpl : IFormattedTextImpl - { - public FormattedTextImpl( - string text, - string fontFamily, - double fontSize, - FontStyle fontStyle, - TextAlignment textAlignment, - FontWeight fontWeight) - { - String = text; - TextPaint = new ATextPaint { TextAlign = textAlignment.ToAndroidGraphics() }; - var typefaceStyle = fontStyle.ToAndroidGraphicsTypefaceStyle(fontWeight); - var typeface = fontStyle.ToAndroidGraphicsTypeface(fontWeight); - TextPaint.SetTypeface(typeface); - TextPaint.TextSize = PointUnitService.Instance.PerspexToNativeFontSize(fontSize); - - Aligment = textAlignment.ToAndroidGraphicsLayoutAligment(); - - var rect = new ARect(); - TextPaint.GetTextBounds(String, 0, String.Length, rect); - //or use measure text to give us other opinion for the text ??? - //double tw = TextFormatting.MeasureText(String, 0, String.Length); - - //give few pixels in advance just in case - _initialSize = PointUnitService.Instance.NativeToPerspex(new Size(rect.Right, rect.Bottom)); - Constraint = _initialSize; - } - - private AAllignment Aligment; - - public string String { get; } - - public ATextPaint TextPaint { get; } - - private Size _initialSize; - - public Size Constraint { get; set; } - - public void Dispose() - { - } - - private StaticLayout _layout = null; - private double _layoutBuildWidth = 0; - - private Dictionary> _localCachedValues = new Dictionary>(); - - private T GetLocalCachedValue(string name, object forKey, Func getFunc) - { - KeyValuePair kvp = default(KeyValuePair); - - bool create = true; - if (_localCachedValues.ContainsKey(name)) - { - kvp = _localCachedValues[name]; - create = kvp.Key != forKey; - } - - if (create) - { - kvp = new KeyValuePair(forKey, getFunc()); - _localCachedValues[name] = kvp; - } - - return (T)kvp.Value; - } - - public StaticLayout TextLayout - { - get - { - if (_layout == null || Math.Abs(_layoutBuildWidth - Constraint.Width) > 1) - { - var newWidth = (Constraint.Width > int.MaxValue ? _initialSize.Width : Constraint.Width) + 10; - - double widthDiff = _layoutBuildWidth - newWidth; - - if (_layout == null || widthDiff < 0) - { - _layoutBuildWidth = newWidth; - _layout = new StaticLayout(String, TextPaint, PointUnitService.Instance.PerspexToNativeXInt(_layoutBuildWidth), Aligment, 1.0f, 0.0f, false); - _localCachedValues.Clear(); - } - } - - return _layout; - } - } - - public IEnumerable GetLines() - { - return GetLocalCachedValue("GetLines", "GetLines", () => - { - List result = new List(); - for (int i = 0; i < TextLayout.LineCount; i++) - { - int start = TextLayout.GetLineStart(i); - int end = TextLayout.GetLineEnd(i); - //string lineContent = String.Substring(start, end - start); - result.Add(new FormattedTextLine(end - start, PointUnitService.Instance.NativeToPerspexY(TextLayout.GetLineTop(i) - TextLayout.GetLineBottom(i)))); - } - return result; - }); - } - - public TextHitTestResult HitTestPoint(Point ppoint) - { - return GetLocalCachedValue("HitTestPoint", ppoint, () => - { - var point = PointUnitService.Instance.PerspexToNative(ppoint); - - bool inside = point.X >= 0 && point.X <= TextLayout.Width && point.Y >= 0 && point.Y <= TextLayout.Height; - int index = -1; - - if (inside) - { - int line = this.TextLayout.GetLineForVertical(Convert.ToInt32(point.Y)); - index = this.TextLayout.GetOffsetForHorizontal(line, (float)point.X); - } - - return new TextHitTestResult { IsInside = inside, IsTrailing = false, TextPosition = index }; - }); - } - - public Rect HitTestTextPosition(int index) - { - return - GetLocalCachedValue("HitTestTextPosition", index, () => - { - int line = TextLayout.GetLineForOffset(index); - int top = TextLayout.GetLineTop(line); - int bottom = TextLayout.GetLineBottom(line); - double left = TextLayout.GetPrimaryHorizontal(index); - - double right = String.Length > index + 1 ? TextLayout.GetPrimaryHorizontal(index + 1) : left; - - return PointUnitService.Instance.NativeToPerspex(new Rect(left, top, right - left, bottom - top)); - }); - } - - public IEnumerable HitTestTextRange(int index, int length) - { - int startLine = TextLayout.GetLineForOffset(index); - int endIndex = index + length; - int endLine = TextLayout.GetLineForOffset(endIndex); - - for (int i = startLine; i <= endLine; i++) - { - int top = TextLayout.GetLineTop(i); - int bottom = TextLayout.GetLineBottom(i); - - double left = 0, right = 0; - - if (startLine == i) - { - left = TextLayout.GetPrimaryHorizontal(index); - } - else - { - left = TextLayout.GetLineLeft(i); - } - - if (endLine == i) - { - right = TextLayout.GetPrimaryHorizontal(endIndex); - } - else - { - right = TextLayout.GetLineRight(i); - } - - yield return PointUnitService.Instance.NativeToPerspex(new Rect(left, top, right - left, bottom - top)); - } - } - - public Size Measure() - { - return PointUnitService.Instance.NativeToPerspex(new Size(this.TextLayout.Width, this.TextLayout.Height)); - } - - public void SetForegroundBrush(Brush brush, int startIndex, int length) - { - var scb = brush as SolidColorBrush; - if (scb != null) - { - TextPaint.Color = scb.Color.ToAndroidGraphics(); - } - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/RenderTarget.cs b/src/Android/Perspex.Android/CanvasRendering/RenderTarget.cs deleted file mode 100644 index 059f858b7a..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/RenderTarget.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Android.Platform.CanvasPlatform; -using Perspex.Android.Platform.Specific; -using Perspex.Platform; -using AG = Android.Graphics; - -namespace Perspex.Android.CanvasRendering -{ - /// - /// A android render target. - /// - public class RenderTarget : IRenderTarget - { - private readonly AG.Bitmap _nativeBitmap; - private IAndroidCanvasView _window; - - /// - /// Initializes a new instance of the class. - /// - /// The window. - /// The width of the window. - /// The height of the window. - public RenderTarget(IAndroidCanvasView window) - { - _window = window; - } - - public RenderTarget(AG.Bitmap surface) - { - _nativeBitmap = surface; - } - - /// - /// Resizes the renderer. - /// - /// The new width. - /// The new height. - public void Resize(int width, int height) - { - if (_nativeBitmap != null) - { - this._nativeBitmap.Reconfigure(width, height, AG.Bitmap.Config.Argb8888); - } - } - - /// - /// Creates a DrawingContext that targets a platform-specific resource. - /// - /// A surface wrapped in an . - public Perspex.Media.DrawingContext CreateDrawingContext() - { - var canvas = _nativeBitmap != null ? new AG.Canvas(this._nativeBitmap) : _window.Canvas; - return new Perspex.Media.DrawingContext(new DrawingContextImpl(canvas, _window != null ? _window.VisualCaches : null)); - } - - public void Dispose() - { - this._nativeBitmap?.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/RenderTargetBitmapImpl.cs b/src/Android/Perspex.Android/CanvasRendering/RenderTargetBitmapImpl.cs deleted file mode 100644 index 900798f9ba..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/RenderTargetBitmapImpl.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Platform; -using System.IO; -using AG = Android.Graphics; - -namespace Perspex.Android.CanvasRendering -{ - public class RenderTargetBitmapImpl : IRenderTargetBitmapImpl - { - private readonly RenderTarget _renderTarget; - - public RenderTargetBitmapImpl(AG.Bitmap surface) - { - Surface = surface; - _renderTarget = new RenderTarget(Surface); - } - - public int PixelWidth => Surface.Width; - - public int PixelHeight => Surface.Height; - - public void Dispose() - { - _renderTarget.Dispose(); - } - - public AG.Bitmap Surface { get; } - - public void Save(string fileName) - { - using (var f = File.OpenWrite(fileName)) - { - Surface.Compress(AG.Bitmap.CompressFormat.Png, 100, f); - } - } - - public Perspex.Media.DrawingContext CreateDrawingContext() - { - return _renderTarget.CreateDrawingContext(); - } - - //void IRenderTarget.Resize(int width, int height) - //{ - // this._renderTarget.Resize(width, height); - //} - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/CanvasRendering/StreamGeometryImpl.cs b/src/Android/Perspex.Android/CanvasRendering/StreamGeometryImpl.cs deleted file mode 100644 index a57478a331..0000000000 --- a/src/Android/Perspex.Android/CanvasRendering/StreamGeometryImpl.cs +++ /dev/null @@ -1,158 +0,0 @@ -using Android.Graphics; -using Perspex.Media; -using Perspex.Platform; -using System; -using System.Linq; -using APath = Android.Graphics.Path; -using ARect = Android.Graphics.RectF; - -namespace Perspex.Android.CanvasRendering -{ - public class StreamGeometryImpl : IStreamGeometryImpl - { - private readonly StreamGeometryContextImpl _impl; - private Matrix _transform = Matrix.Identity; - - public StreamGeometryImpl() - { - _impl = new StreamGeometryContextImpl(null); - } - - public StreamGeometryImpl(StreamGeometryContextImpl impl) - { - _impl = impl; - } - - public APath Path => _impl.Path; - - public Rect Bounds => _impl.CalculatedBounds; - - public Matrix Transform - { - get { return _transform; } - set - { - if (value == Transform) return; - if (!value.IsIdentity) - { - _transform = value; - - Path.Transform(_transform.ToAndroidGraphics()); - } - } - } - - public Rect GetRenderBounds(double strokeThickness) - { - return Bounds.Inflate(strokeThickness); - } - - public IStreamGeometryImpl Clone() - { - return new StreamGeometryImpl(_impl); - } - - public IStreamGeometryContextImpl Open() - { - return _impl; - } - } - - public class StreamGeometryContextImpl : IStreamGeometryContextImpl - { - private double _top = double.MaxValue; - private double _left = double.MaxValue; - private double _bottom = 1; - private double _right = 1; - - public StreamGeometryContextImpl(APath path = null) - { - Path = path != null ? new APath(path) : new APath(); - Path.AddRect(new ARect(), APath.Direction.Cw); - } - - public APath Path { get; } - - public Rect PathBounds - { - get - { - var _bounds = new ARect(); - - Path.ComputeBounds(_bounds, true); - return _bounds.ToPerspex(); - } - } - - public Rect CalculatedBounds - { - get - { - return new Rect(_left, _top, _right - _left, _bottom - _top); - } - } - - public void Dispose() - { - } - - private void ProcessBounds(params Point[] points) - { - _top = Math.Min(_top, points.Min(p => p.Y)); - _left = Math.Min(_left, points.Min(p => p.X)); - _bottom = Math.Max(_bottom, points.Max(p => p.Y)); - _right = Math.Max(_right, points.Max(p => p.X)); - } - - public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) - { - ProcessBounds(point); - - Path.ArcTo(new Rect(point, size).ToAndroidGraphicsF(), 0, (float)rotationAngle); - } - - public void BeginFigure(Point pstartPoint, bool isFilled) - { - ProcessBounds(pstartPoint); - var sp = pstartPoint.ToAndroidGraphics(); - - Path.MoveTo(sp.X, sp.Y); - } - - public void BezierTo(Point ppoint1, Point ppoint2, Point ppoint3) - { - ProcessBounds(ppoint1, ppoint2, ppoint3); - var point1 = ppoint1.ToAndroidGraphics(); - var point2 = ppoint2.ToAndroidGraphics(); - var point3 = ppoint3.ToAndroidGraphics(); - - Path.CubicTo(point1.X, point1.Y, - point2.X, point2.Y, - point3.X, point3.Y); - } - - public void LineTo(Point ppoint) - { - ProcessBounds(ppoint); - var point = ppoint.ToAndroidGraphics(); - - Path.LineTo(point.X, point.Y); - } - - public void EndFigure(bool isClosed) - { - if (Path != null) - if (isClosed) - Path.Close(); - } - - public void QuadTo(Point ppoint1, Point ppoint2) - { - ProcessBounds(ppoint1, ppoint2); - var point1 = ppoint1.ToAndroidGraphics(); - var point2 = ppoint2.ToAndroidGraphics(); - - Path.QuadTo(point1.X, point1.Y, point2.X, point2.Y); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Perspex.Android.csproj b/src/Android/Perspex.Android/Perspex.Android.csproj index 8b06bae59d..6af3c2a736 100644 --- a/src/Android/Perspex.Android/Perspex.Android.csproj +++ b/src/Android/Perspex.Android/Perspex.Android.csproj @@ -66,39 +66,19 @@ - - - + - - - - - - - - - - - - - - - - - - diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/IAndroidCanvasView.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/IAndroidCanvasView.cs deleted file mode 100644 index 54790d07f5..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/IAndroidCanvasView.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Android.Graphics; -using Perspex.Android.Platform.Specific; -using System; -using System.Collections.Generic; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public interface IAndroidCanvasView : IAndroidView - { - Canvas Canvas { get; } - - Dictionary VisualCaches { get; } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/IAndroidViewSupportRender.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/IAndroidViewSupportRender.cs deleted file mode 100644 index a409afebf6..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/IAndroidViewSupportRender.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Android.Graphics; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public interface IAndroidViewSupportRender - { - void PreRender(Canvas canvas, Rect rect); - - void Render(Canvas canvas, Rect rect); - - void PostRender(Canvas canvas, Rect rect); - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/MainWindowImpl.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/MainWindowImpl.cs deleted file mode 100644 index 0eda56c3bd..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/MainWindowImpl.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Android.Views; -using Perspex.Android.Platform.Specific; -using Perspex.Android.Platform.Specific.Helpers; -using Perspex.Input; -using Perspex.Platform; -using AG = Android.Graphics; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public class MainWindowImpl : - //SurfaceWindowImpl - WindowImpl - , IWindowImpl - { - private IPointUnitService _pointService = PointUnitService.Instance; - - protected override void Init() - { - base.Init(); - - HandleEvents = true; - _keyboardHelper.ActivateAutoShowKeybord(); - } - - private int _statusbarHeight = -1; - - private int StatusBarHeight - { - get - { - if (_statusbarHeight < 0) - { - var a = PerspexLocator.Current.GetService().Activity; - AG.Rect rectangle = new AG.Rect(); - Window window = a.Window; - window.DecorView.GetWindowVisibleDisplayFrame(rectangle); - int statusBarHeight = rectangle.Top; - //int contentViewTop = - // window.FindViewById(Window.IdAndroidContent).Top; - //int titleBarHeight = contentViewTop - statusBarHeight; - _statusbarHeight = statusBarHeight; - } - return _statusbarHeight; - } - } - - public override Point GetPerspexPointFromEvent(MotionEvent e) - { - //toolbar is on top of android screen and it's height is 50 ??? - //may be dependent from dpi ??? - //return base.GetPerspexPointFromEvent(e); - //return new Point(e.GetX(0), e.GetY(0) + StatusBarHeight); - - var point = new Point(e.GetX(0), e.GetY(0) + (DrawType == ViewDrawType.CanvasOnDraw ? StatusBarHeight : 0)); - return _pointService.NativeToPerspex(point); - } - - void ITopLevelImpl.Show() - { - (Parent as ViewGroup)?.RemoveAllViews(); - PerspexLocator.Current.GetService().ContentView = this; - this.Visibility = ViewStates.Visible; - } - - void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) - { - base.SetInputRoot(inputRoot); - _keyboardHelper.UpdateKeyboardState(inputRoot); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/PointUnitService.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/PointUnitService.cs deleted file mode 100644 index e782f83f3c..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/PointUnitService.cs +++ /dev/null @@ -1,184 +0,0 @@ -using Perspex.Android.Platform.Specific; -using System; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public enum PointUnit - { - Pixel, - DP, //device independent pixel - Custom // CustomScale - } - - public interface IPointUnitService - { - double ScaleX { get; } - double ScaleY { get; } - double FontScale { get; } - - double NativeToPerspexX(double x); - - double NativeToPerspexY(double y); - - double PerspexToNativeX(double x); - - double PerspexToNativeY(double y); - - float PerspexToNativeFontSize(double fontSize); - } - - public class PointUnitService : IPointUnitService - { - public static IPointUnitService Instance => PerspexLocator.Current.GetService() ?? new PointUnitService(); - - private PointUnit _pointUnit; - - public PointUnit PointUnit - { - get { return _pointUnit; } - set - { - _pointUnit = value; - OnPointUnitChanged(); - } - } - - public double ScaleX { get; set; } - - public double ScaleY { get; set; } - - public double FontScale { get; set; } - - public PointUnitService() - { - PointUnit = AndroidPlatform.Instance.DefaultPointUnit; - //ScaleX = 1; - //ScaleY = 1; - ////FontScale = 1; - //ScaleX = 2; - //ScaleY = 2; - //FontScale = 2; - } - - private void OnPointUnitChanged() - { - switch (PointUnit) - { - case PointUnit.Pixel: - ScaleX = 1; - ScaleY = 1; - FontScale = 1; - break; - - case PointUnit.DP: - { - //get android metrics for device pixel format - var activity = PerspexLocator.Current.GetService().Activity; - var dm = activity.Resources.DisplayMetrics; - double scale = Math.Round((double)dm.ScaledDensity, 2); - ScaleX = scale; - ScaleY = scale; - FontScale = scale; - } - break; - - case PointUnit.Custom: - { - double scale = 2; - ScaleX = scale; - ScaleY = scale; - FontScale = scale; - } - break; - } - } - - public double NativeToPerspexX(double x) => ScaleX == 1 ? x : RoundToPerspex(x / ScaleX); - - public double NativeToPerspexY(double y) => ScaleY == 1 ? y : RoundToPerspex(y / ScaleY); - - public double PerspexToNativeX(double x) => ScaleX == 1 ? x : RoundToNative(ScaleX * x); - - public double PerspexToNativeY(double y) => ScaleY == 1 ? y : RoundToNative(ScaleY * y); - - public float PerspexToNativeFontSize(double fontSize) - { - if (FontScale == 1) return (float)fontSize; - return (float)Math.Round(FontScale * fontSize, 1); - } - - private static double RoundToPerspex(double v) - { - // return Math.Ceiling(v); - return Math.Round(v, 5); - } - - private static double RoundToNative(double v) - { - //return Math.Ceiling(v); - return Math.Round(v, 2); - } - } - - public static class PointServiceExtensions - { - //public static Matrix PerspexToNative(this IPointService ps, Matrix m) - //{ - // if (ps.ScaleX == ps.ScaleY && ps.ScaleX == 1) return m; - - // return new Matrix(m.M11, m.M12, m.M21, m.M22, m.M31 * ps.ScaleX, m.M32 * ps.ScaleY); - //} - - //public static double PerspexToNative(this IPointService service, double x) - //{ - // if (service.ScaleX == 1) return x; - // return x * service.ScaleX; - //} - - private static int RoundToInt(double v) - { - return (int)Math.Round(v, 0); - } - - public static double NativeToPerspex(this IPointUnitService ps, double x) => ps.NativeToPerspexX(x); - - public static float PerspexToNativeXF(this IPointUnitService ps, double x) => (float)ps.PerspexToNativeX(x); - - public static float PerspexToNativeYF(this IPointUnitService ps, double y) => (float)ps.PerspexToNativeY(y); - - public static int PerspexToNativeXInt(this IPointUnitService ps, double x) => RoundToInt(ps.PerspexToNativeX(x)); - - public static int PerspexToNativeYInt(this IPointUnitService ps, double y) => RoundToInt(ps.PerspexToNativeX(y)); - - public static Point NativeToPerspex(this IPointUnitService ps, Point point) => (ps.ScaleY == 1 && ps.ScaleX == 1) ? point : new Point(ps.NativeToPerspexX(point.X), ps.NativeToPerspexY(point.Y)); - - public static Point PerspexToNative(this IPointUnitService ps, Point point) => (ps.ScaleY == 1 && ps.ScaleX == 1) ? point : new Point(ps.PerspexToNativeX(point.X), ps.PerspexToNativeY(point.Y)); - - public static Size NativeToPerspex(this IPointUnitService service, Size size) - { - if (service.ScaleX == service.ScaleY && service.ScaleX == 1) return size; - - return new Size(size.Width / service.ScaleX, size.Height / service.ScaleY); - } - - public static Size PerspexToNative(this IPointUnitService service, Size size) - { - if (service.ScaleX == service.ScaleY && service.ScaleX == 1) return size; - return new Size(size.Width * service.ScaleX, size.Height * service.ScaleY); - } - - public static Rect NativeToPerspex(this IPointUnitService service, Rect rect) - { - if (service.ScaleX == service.ScaleY && service.ScaleX == 1) return rect; - - return new Rect(rect.X / service.ScaleX, rect.Y / service.ScaleY, rect.Width / service.ScaleX, rect.Height / service.ScaleY); - } - - public static Rect PerspexToNative(this IPointUnitService service, Rect rect) - { - if (service.ScaleX == service.ScaleY && service.ScaleX == 1) return rect; - - return new Rect(rect.X * service.ScaleX, rect.Y * service.ScaleY, rect.Width * service.ScaleX, rect.Height * service.ScaleY); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/PopupImpl.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/PopupImpl.cs deleted file mode 100644 index e958e45862..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/PopupImpl.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Android.Content; -using Android.Views; -using Android.Widget; -using Perspex.Android.Platform.Specific; -using Perspex.Input; -using Perspex.Input.Raw; -using Perspex.Platform; -using System; -using AG = Android.Graphics; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public class PopupImpl : PopupWindow, IPopupImpl, IPlatformHandle - { - private class PopupPerspexViewContent : WindowImpl - { - private Func _funcDispatchTouchEvent; - - public PopupPerspexViewContent(Context context, Func funcDispatchTouchEvent) : base(context) - { - this._funcDispatchTouchEvent = funcDispatchTouchEvent; - } - - public override bool DispatchTouchEvent(MotionEvent e) - { - bool? res = _funcDispatchTouchEvent(e); - - return res == null ? base.DispatchTouchEvent(e) : res.Value; - } - } - - private PopupPerspexViewContent content; - - private View mainView; - - //public PopupImpl(Context context) : base(context) - public PopupImpl() - { - ContentView = content = new PopupPerspexViewContent(PerspexLocator.Current.GetService().Activity, DispatchTouchEvent); - ContentView.Background = new AG.Drawables.ColorDrawable(AG.Color.Transparent); - mainView = PerspexLocator.Current.GetService().ContentView.View; - //Background = new AG.Drawables.ColorDrawable(AG.Color.); - } - - //public PopupImpl() : this(PerspexLocator.Current.GetService().Activity) - //{ - //} - - private bool? DispatchTouchEvent(MotionEvent e) - { - var p = content.GetPerspexPointFromEvent(e); - - Rect clientBounds = new Rect(ClientSize); - - if (clientBounds.Contains(p)) - { - return null; - } - - return mainView.DispatchTouchEvent(e); - } - - public Size MaxClientSize => content.MaxClientSize; - - public Action Activated { get { return (content as ITopLevelImpl).Activated; } set { (content as ITopLevelImpl).Activated = value; } } - - public Size ClientSize { get { return content.ClientSize; } set { content.ClientSize = value; } } - - public Action Closed { get { return content.Closed; } set { content.Closed = value; } } - - public Action Deactivated { get { return content.Deactivated; } set { content.Deactivated = value; } } - - public Action Input { get { return content.Input; } set { content.Input = value; } } - - public Action Paint { get { return content.Paint; } set { content.Paint = value; } } - - public Action Resized { get { return content.Resized; } set { content.Resized = value; } } - - IntPtr IPlatformHandle.Handle => content.Handle; - - IPlatformHandle ITopLevelImpl.Handle => content; - - public string HandleDescriptor => "PopupImpl"; - - public void Activate() => content.Activate(); - - public void Invalidate(Rect rect) => content.Invalidate(rect); - - public Point PointToScreen(Point point) - { - return content.PointToScreen(point); - } - - public void SetCursor(IPlatformHandle cursor) - { - content.SetCursor(cursor); - } - - public void SetInputRoot(IInputRoot inputRoot) - { - content.SetInputRoot(inputRoot); - } - - private Point position; - - public void SetPosition(Point p) - { - position = p; - } - - public void Show() - { - content.HandleEvents = true; - var ps = PointUnitService.Instance; - //content.Activate(); - Width = ps.PerspexToNativeXInt(MaxClientSize.Width - position.X); - Height = ps.PerspexToNativeYInt(MaxClientSize.Height - position.Y); - content.LayoutParameters = new ViewGroup.LayoutParams(Width, Height); - // content.ClientSize = new Size(MaxClientSize.Width - position.X, MaxClientSize.Height - position.Y); - //Width = Convert.ToInt32(ClientSize.Width); - //Height = Convert.ToInt32(ClientSize.Height); - - base.ShowAtLocation(mainView, GravityFlags.Top | GravityFlags.Left, ps.PerspexToNativeXInt(position.X), ps.PerspexToNativeYInt(position.Y)); - content.Invalidate(); - } - - public void Hide() - { - content.HandleEvents = false; - //content.Hide(); - base.Dismiss(); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/Specific/Helpers/AndroidViewRenderHelpers.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/Specific/Helpers/AndroidViewRenderHelpers.cs deleted file mode 100644 index 0cd7e891ff..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/Specific/Helpers/AndroidViewRenderHelpers.cs +++ /dev/null @@ -1,688 +0,0 @@ -using Android.Graphics; -using Android.Runtime; -using Android.Text; -using Android.Util; -using Android.Views; -using Perspex.Android.CanvasRendering; -using Perspex.Android.Platform.Specific.Helpers; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using P = Perspex.Platform; - -namespace Perspex.Android.Platform.CanvasPlatform.Specific.Helpers -{ - public abstract class AndroidViewRenderHelper : Java.Lang.Object, IDisposable where TView : View, P.IWindowImpl, IAndroidViewSupportRender - { - private static bool _debug = false; - - protected AndroidViewRenderHelper(TView view) - { - this.View = view; - VisualCaches = null; - } - - public Dictionary VisualCaches { get; protected set; } - - public abstract void OnDraw(Canvas canvas); - - public abstract void Invalidate(Rect rect); - - public TView View { get; private set; } - - public ViewDrawType DrawType { get; private set; } - - public static AndroidViewRenderHelper Create(TView view, ViewDrawType drawType) - { - AndroidViewRenderHelper result; - switch (drawType) - { - case ViewDrawType.BitmapBackgroundRender: - result = new BitmapBackgroundRenderHelper(view); - break; - - case ViewDrawType.BitmapOnPreDraw: - result = new BitmapPreDrawRenderHelper(view); - break; - - case ViewDrawType.CanvasOnDraw: - result = new CanvasOnDrawAndroidViewRenderHelper(view); - break; - - default: - throw new NotSupportedException(); - } - - Init(result, drawType); - - return result; - } - - protected static void Init(AndroidViewRenderHelper helper, ViewDrawType drawType) - { - helper.DrawType = drawType; - helper.SetDebugInfo("DrawType", drawType.ToString()); - } - - public virtual new void Dispose() - { - View = null; - _debugInfoPaint?.Dispose(); - } - - public Dictionary DebugInfo { get; } = new Dictionary(); - - protected void SetDebugInfo(string key, string value) => DebugInfo[key] = value; - - private const int _avgValuesForStat = 50; - - private Dictionary> _renderStats = new Dictionary>(); - - protected void UpdateRenderStat(string key, double ms) - { - Queue statsQueue; - if (!_renderStats.TryGetValue(key, out statsQueue)) - { - statsQueue = new Queue(); - _renderStats[key] = statsQueue; - } - - statsQueue.Enqueue(ms); - if (statsQueue.Count > _avgValuesForStat) statsQueue.Dequeue(); - - SetDebugInfo(key, ms.ToString("0.0")); - SetDebugInfo($"a{key}", (statsQueue.Average()).ToString("0.0")); - } - - protected void RenderView(Canvas canvas, Rect rect) - { - DateTime begin = DateTime.Now; - - View.PreRender(canvas, rect); - View.Render(canvas, rect); - View.PostRender(canvas, rect); - - TimeSpan duration = DateTime.Now - begin; - - if (_debug) Log.Debug("AndroidViewRenderHelper", $"RenderView {duration}"); - - UpdateRenderStat("RenderView", duration.TotalMilliseconds); - UpdateRenderStat("mfps", 1000 / duration.TotalMilliseconds); - } - - private Paint _debugInfoPaint = null; - - public void DrawDebugInfoToCanvas(Canvas canvas) - { - if (!AndroidPlatform.Instance.DrawDebugInfo) return; - - if (DebugInfo.Count == 0) return; - - if (_debugInfoPaint == null) _debugInfoPaint = new TextPaint(PaintFlags.AntiAlias) { Color = Color.Red, TextAlign = Paint.Align.Left, TextSize = 20 }; - - var sb = new StringBuilder(); - foreach (var o in DebugInfo) - { - sb.Append($"{o.Key} = {o.Value}; "); - } - string sdb = sb.ToString(); - var r = new global::Android.Graphics.Rect(); - _debugInfoPaint.GetTextBounds(sdb, 0, sdb.Length, r); - - canvas.DrawText(sdb, View.Width - r.Right, View.Height - r.Bottom, _debugInfoPaint); - - if (_debug) Log.Debug("AndroidViewRenderHelper", sdb); - } - } - - public class CanvasOnDrawAndroidViewRenderHelper : AndroidViewRenderHelper where TView : View, P.IWindowImpl, IAndroidViewSupportRender - { - private Rect _rect; - - public CanvasOnDrawAndroidViewRenderHelper(TView view) : base(view) - { - } - - public override void Invalidate(Rect rect) - { - _rect = rect; - View.Invalidate(rect.ToAndroidGraphics()); - } - - public override void OnDraw(Canvas canvas) - { - RenderView(canvas, _rect); - } - - public override void Dispose() - { - base.Dispose(); - } - } - - public class BitmapBackgroundRenderHelper : AndroidViewRenderHelper where TView : View, P.IWindowImpl, IAndroidViewSupportRender - { - private bool _debug = WindowImpl._debug; - private Bitmap _bitmap; - private Rect _rect; - private Paint _paint = new Paint(); - private ConcurrentStack _invalidateRects = new ConcurrentStack(); - private object _invalidateRectsSync = new object(); - private object _drawSync = new object(); - private Stack _renderingBitmapsCache = new Stack(); - private Dictionary _bmCanvases = new Dictionary(); - private CancellationTokenSource _cancelationTokenSource; - - public BitmapBackgroundRenderHelper(TView view) : base(view) - { - _cancelationTokenSource = new CancellationTokenSource(); - VisualCaches = new Dictionary(); - Task.Factory.StartNew(RenderingLoop, _cancelationTokenSource.Token, _cancelationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Current); - } - - public override void Invalidate(Rect rect) - { - _rect = rect; - _invalidateRects.Push(rect); - lock (_invalidateRectsSync) - { - Monitor.Pulse(_invalidateRectsSync); - } - } - - public override void OnDraw(Canvas canvas) - { - var begin = DateTime.Now; - lock (_drawSync) - { - if (_bitmap != null) - { - canvas.DrawBitmap(_bitmap, 0, 0, _paint); - } - } - - UpdateRenderStat("OnDraw", (DateTime.Now - begin).TotalMilliseconds); - } - - private void RenderingLoop(object obj) - { - CancellationToken token = (CancellationToken)obj; - if (_debug) Log.Debug("render", "RenderingLoop Start ..."); - - AndroidPlatform.Instance.RegisterRenderingTaskId(Task.CurrentId.Value); - - while (!token.IsCancellationRequested) - { - try - { - Rect rect = default(Rect); - bool hasRect = false; - - hasRect = _invalidateRects.Count > 0; ; - if (!hasRect) - { - lock (_invalidateRectsSync) - { - hasRect = Monitor.Wait(_invalidateRectsSync, 1000); - } - } - - if (!hasRect) - { - DisposeVisualCaches(); - continue; - } - - if (_invalidateRects.Count < 1) continue; - int rCnt = _invalidateRects.Count; - - Rect[] rects = new Rect[rCnt > 1 ? (rCnt - 1) : 1]; - int cnt = _invalidateRects.TryPopRange(rects, 0, rects.Length); - if (_debug) Log.Debug("render", $"RenderingLoop processing {cnt} rects"); - if (cnt == 1) - { - rect = rects[0]; - //assuming this is the last frame so we dispose the caches - DisposeVisualCaches(); - } - else if (cnt > 1) - { - //for now all the rects are the same but may be in the future this can change - var minX = rects.Min(r => r.X); - var minY = rects.Min(r => r.Y); - var maxRight = rects.Max(r => r.Right); - var maxBottom = rects.Max(r => r.Bottom); - rect = new Rect(minX, minY, maxRight - minX, maxBottom - minY); - } - else - { - //Should never happend - hasRect = false; - } - - if (hasRect) - { - Render(rect); - } - } - catch (Exception e) - { - Log.Debug("render", "RenderingLoop Exception {0} ...", e); - } - } - AndroidPlatform.Instance.UnRegisterRenderingTaskId(Task.CurrentId.Value); - Log.Debug("render", "RenderingLoop End ..."); - } - - private void Render(Rect rect) - { - DateTime begin = DateTime.Now; - if (_debug) Log.Debug("render", $"RenderingLoop new invalidation ... {rect} {begin}"); - Bitmap bitmap; - - int w = View.Width; - int h = View.Height; - - if (w == 0) - { - var s = PointUnitService.Instance.PerspexToNative(View.ClientSize); - w = (int)s.Width; - h = (int)s.Height; - } - - if (_renderingBitmapsCache.Count > 0) - { - // _renderingBitmapsCache.TryPop(out bitmap); - bitmap = _renderingBitmapsCache.Pop(); - } - else - { - bitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888); - } - - if (bitmap.Width != w || bitmap.Height != h) - { - bitmap.Dispose(); - bitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888); - foreach (var c in _bmCanvases) - { - c.Value.Dispose(); - } - _bmCanvases.Clear(); - } - - Canvas canvas; - if (!_bmCanvases.TryGetValue(bitmap, out canvas)) - { - canvas = new Canvas(bitmap); - _bmCanvases.Add(bitmap, canvas); - } - - RenderView(canvas, _rect); - - //???no need dispose canvas is cached - //canvas.Dispose(); - lock (_drawSync) - { - if (_bitmap != null) _renderingBitmapsCache.Push(_bitmap); - _bitmap = bitmap; - } - var nr = rect.ToAndroidGraphics(); - - View.PostInvalidate(nr.Left, nr.Top, nr.Right, nr.Bottom); - //View.PostInvalidateDelayed(1, nr.Left, nr.Top, nr.Right, nr.Bottom); - } - - private void DisposeVisualCaches() - { - lock (_drawSync) - { - if (_debug) Log.Debug("render", $"RenderingLoop disposing {VisualCaches.Count} visual caches"); - foreach (var vc in VisualCaches) - { - vc.Value.Dispose(); - } - - VisualCaches.Clear(); - } - } - - public override void Dispose() - { - base.Dispose(); - _cancelationTokenSource.Cancel(); - _cancelationTokenSource = null; - } - } - - public class BitmapPreDrawRenderHelper : AndroidViewRenderHelper where TView : View, P.IWindowImpl, IAndroidViewSupportRender - { - private class OnPreDrawListener : Java.Lang.Object, ViewTreeObserver.IOnPreDrawListener - { - private Func _preDraw; - - public OnPreDrawListener(Func preDraw) - { - _preDraw = preDraw; - } - - public bool OnPreDraw() - { - return _preDraw(); - } - } - - private Bitmap _bitmap; - private Rect _rect; - private Paint _paint = new Paint(); - private OnPreDrawListener _listener; - - public BitmapPreDrawRenderHelper(TView view) : base(view) - { - _listener = new OnPreDrawListener(OnPreDraw); - View.ViewTreeObserver.AddOnPreDrawListener(_listener); - } - - public override void Dispose() - { - base.Dispose(); - View.ViewTreeObserver.RemoveOnPreDrawListener(_listener); - _listener.Dispose(); - _bitmap.Dispose(); - _paint.Dispose(); - } - - public override void Invalidate(Rect rect) - { - _rect = rect; - View.Invalidate(rect.ToAndroidGraphics()); - } - - public override void OnDraw(Canvas canvas) - { - var begin = DateTime.Now; - - if (_bitmap != null) - { - canvas.DrawBitmap(_bitmap, 0, 0, _paint); - } - - UpdateRenderStat("OnDraw", (DateTime.Now - begin).TotalMilliseconds); - } - - public bool OnPreDraw() - { - int w = View.Width; - int h = View.Height; - Bitmap bitmap = _bitmap; - if (bitmap == null) - { - bitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888); - } - else if (bitmap.Width != w || bitmap.Height != h) - { - bitmap.Dispose(); - bitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888); - } - using (var canvas = new Canvas(bitmap)) - { - RenderView(canvas, _rect); - } - _bitmap = bitmap; - return true; - } - } - - public class SurfaceViewRenderHelper : AndroidViewRenderHelper where TView : SurfaceView, P.IWindowImpl, IAndroidViewSupportRender - { - private class SurfaceHolderCallback : Java.Lang.Object, ISurfaceHolderCallback//, ISurfaceHolderCallback2 - { - private SurfaceViewRenderHelper _parent; - - public SurfaceHolderCallback(SurfaceViewRenderHelper parent) - { - _parent = parent; - } - - public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height) - { - _parent.SurfaceChanged(holder, format, width, height); - } - - public void SurfaceCreated(ISurfaceHolder holder) - { - _parent.SurfaceCreated(holder); - } - - public void SurfaceDestroyed(ISurfaceHolder holder) - { - _parent.SurfaceDestroyed(holder); - } - - public void SurfaceRedrawNeeded(ISurfaceHolder holder) - { - _parent.SurfaceRedrawNeeded(holder); - } - } - - public int DelayBetweenDrawms { get; set; } - protected ISurfaceHolder _holder; - private Task _task; - private CancellationTokenSource _cancelationTokenSource; - private CancellationToken _cancelationToken; - - private ConcurrentStack _pendingInvalidations = new ConcurrentStack(); - private object _invalidationRectsSync = new object(); - - private Format _surfaceFormat = Format.Rgba8888; - private Bitmap.Config _bitmapFormat = Bitmap.Config.Argb8888; - - public static new SurfaceViewRenderHelper Create(TView view, ViewDrawType drawType) - { - SurfaceViewRenderHelper result; - - switch (drawType) - { - case ViewDrawType.SurfaceViewCanvasOnDraw: - result = new SurfaceViewRenderHelper(view); - break; - - default: throw new NotSupportedException(); - } - - Init(result, drawType); - - return result; - } - - public SurfaceViewRenderHelper(TView view) : base(view) - { - //max 16fps -60ms, 25fps - 40ms, max 30fps 30ms, max 60 fps-17ms - DelayBetweenDrawms = 40; - view.Holder.AddCallback(new SurfaceHolderCallback(this)); - } - - public override void Invalidate(Rect rect) - { - lock (_invalidationRectsSync) - { - _pendingInvalidations.Push(rect); - Monitor.Pulse(_invalidationRectsSync); - } - } - - public override void OnDraw(Canvas canvas) - { - //do nothing here we are drawing on another thread - } - - public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height) - { - Log.Debug("SurfaceViewRenderAdapter", $"SurfaceChanged format={format} width ={width} height={height}..."); - - var ps = PointUnitService.Instance; - Size newSize = new Size(ps.NativeToPerspexX(width), ps.NativeToPerspexY(height)); - if (View.ClientSize != newSize) - { - View.ClientSize = newSize; - View.Resized?.Invoke(View.ClientSize); - } - - ScheduleRender(); - } - - public void SurfaceCreated(ISurfaceHolder holder) - { - Log.Debug("SurfaceViewRenderAdapter", "SurfaceCreated ..."); - - _holder = holder; - _holder.SetFormat(_surfaceFormat); - - if (_task != null) - { - StopTask(); - } - - if (_task == null) StartTask(); - - ScheduleRender(); - } - - private void SurfaceRedrawNeeded(ISurfaceHolder holder) - { - Log.Debug("SurfaceViewRenderAdapter", "SurfaceRedrawNeeded ..."); - ScheduleRender(); - } - - private void ScheduleRender() - { - if (_pendingInvalidations.Count > 0) - { - Invalidate(new Rect(0, 0, View.ClientSize.Width, View.ClientSize.Height)); - } - } - - private void RenderingLoop(object obj) - { - AndroidPlatform.Instance.RegisterRenderingTaskId(Task.CurrentId.Value); - Log.Debug("SurfaceViewRenderAdapter", $"DrawingTask Enter Id={Task.CurrentId.Value}... "); - - //sometime the ui is not ready for other thread rendering - Thread.Sleep(10 * DelayBetweenDrawms); - - var cancelationToken = (CancellationToken)obj; - while (!cancelationToken.IsCancellationRequested) - { - try - { - bool waitResult = false; - //wait few miliseconds so we are not heating the processor too much - Thread.Sleep(DelayBetweenDrawms); - - if (_pendingInvalidations.Count < 1) - { - lock (_invalidationRectsSync) - { - waitResult = Monitor.Wait(_invalidationRectsSync, 1000); - Thread.Sleep(0); - } - } - - if (cancelationToken.IsCancellationRequested) break; - - //if invalidations are more than one render one time after this - //so we are sure we have correct state - int requestCnt = _pendingInvalidations.Count > 1 ? _pendingInvalidations.Count - 1 : _pendingInvalidations.Count; - - if (requestCnt < 1) - { - //we can not continue with drawing - continue; - } - - var rects = new Rect[requestCnt]; - int rectsCount = _pendingInvalidations.TryPopRange(rects); - if (rectsCount < 1) - { - //should never happen but who knows - continue; - } - - Rect rect; - if (rectsCount == 1) - { - rect = rects[0]; - } - else - { - double minX = rects.Min(r => r.X); - double minY = rects.Min(r => r.Y); - double maxRight = rects.Max(r => r.Right); - double maxBottom = rects.Max(r => r.Bottom); - rect = new Rect(minX, minY, maxRight - minX, maxBottom - minY); - } - - RenderRect(rect); - } - catch (Exception e) - { - Log.Debug("SurfaceViewRenderAdapter", $"Exception in DrawingTask {e}"); - } - } - Log.Debug("SurfaceViewRenderAdapter", $"DrawingTask Exit Id={Task.CurrentId.Value}..."); - } - - private void RenderRect(Rect rect) - { - //Log.Debug("SurfaceViewRenderAdapter", $"RenderRect Enter rect={rect}... "); - var surfaceCanvas = _holder.LockCanvas(); - - try - { - lock (_holder) - { - RenderView(surfaceCanvas, rect); - } - } - finally - { - _holder.UnlockCanvasAndPost(surfaceCanvas); - } - } - - public void SurfaceDestroyed(ISurfaceHolder holder) - { - StopTask(); - } - - private void StartTask() - { - _cancelationTokenSource = new CancellationTokenSource(); - _cancelationToken = _cancelationTokenSource.Token; - _task = Task.Factory.StartNew(RenderingLoop, _cancelationToken, _cancelationToken); - } - - private void StopTask() - { - try - { - Log.Debug("SurfaceViewRenderAdapter", $"StopTask _cancelationTokenSource != null {_cancelationTokenSource != null}"); - if (_cancelationTokenSource != null) - { - _cancelationTokenSource.Cancel(); - Task.WaitAll(_task); - _cancelationTokenSource = null; - _task = null; - } - } - catch (Exception e) - { - Log.Debug("SurfaceViewRenderAdapter", $"Exception in StopTask DrawingTask.Cancel {e}"); - } - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/SurfaceMainWindowImpl.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/SurfaceMainWindowImpl.cs deleted file mode 100644 index 059d95270a..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/SurfaceMainWindowImpl.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Android.Views; -using Perspex.Android.Platform.Specific; -using Perspex.Input; -using Perspex.Platform; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public class SurfaceMainWindowImpl : SurfaceWindowImpl, IWindowImpl - { - private IPointUnitService _pointService = PointUnitService.Instance; - - protected override void Init() - { - base.Init(); - - HandleEvents = true; - _keyboardHelper.ActivateAutoShowKeybord(); - } - - void ITopLevelImpl.Show() - { - (Parent as ViewGroup)?.RemoveAllViews(); - PerspexLocator.Current.GetService().ContentView = this; - Visibility = ViewStates.Visible; - } - - void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) - { - base.SetInputRoot(inputRoot); - _keyboardHelper.UpdateKeyboardState(inputRoot); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/SurfaceWindowImpl.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/SurfaceWindowImpl.cs deleted file mode 100644 index 988a0a5940..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/SurfaceWindowImpl.cs +++ /dev/null @@ -1,194 +0,0 @@ -using Android.Content; -using Android.Graphics; -using Android.Util; -using Android.Views; -using Perspex.Android.Platform.CanvasPlatform.Specific.Helpers; -using Perspex.Android.Platform.Specific; -using Perspex.Android.Platform.Specific.Helpers; -using Perspex.Input; -using Perspex.Input.Raw; -using Perspex.Platform; -using System; -using System.Collections.Generic; - -using AG = Android.Graphics; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public class SurfaceWindowImpl : SurfaceView, IWindowImpl, IPlatformHandle, IAndroidCanvasView, IAndroidViewSupportRender - { - public SurfaceWindowImpl(Context context) : base(context) - { - DrawType = ViewDrawType.SurfaceViewCanvasOnDraw; - - _keyboardHelper = new AndroidKeyboardEventsHelper(this); - _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, GetPerspexPointFromEvent); - - ClientSize = MaxClientSize; - Resized = size => Invalidate(new Rect(size)); - Init(); - Background = new AG.Drawables.ColorDrawable(AG.Color.Transparent); - } - - public SurfaceWindowImpl() : this(PerspexLocator.Current.GetService().Activity) - { - } - - public void SurfaceRedrawNeeded(ISurfaceHolder holder) - { - Log.Debug("SurfaceView", "SurfaceRedrawNeeded..."); - //TryDraw(holder); - } - - protected override void OnDraw(Canvas canvas) - { - //base.OnDraw(canvas); - this._renderHelper.OnDraw(canvas); - } - - private IPointUnitService _pointService = PointUnitService.Instance; - - public ViewDrawType DrawType { get; } - - private SurfaceViewRenderHelper _renderHelper; - protected AndroidKeyboardEventsHelper _keyboardHelper; - protected AndroidTouchEventsHelper _touchHelper; - - private bool _handleEvents; - - public bool HandleEvents - { - get { return _handleEvents; } - set - { - _handleEvents = value; - _keyboardHelper.HandleEvents = _handleEvents; - } - } - - protected virtual void Init() - { - //SetLayerType(LayerType.Hardware, null); - _renderHelper = SurfaceViewRenderHelper.Create(this, DrawType); - - HandleEvents = false; - - //if the background is not transparent nothing is visible!!! - //this is the case when inherit from GridLayout, not from View - //this.Background = new AG.Drawables.ColorDrawable(AG.Color.Transparent); - } - - public Rect Bounds { get; set; } - - public IInputRoot InputRoot { get; private set; } - IntPtr IPlatformHandle.Handle => Handle; - string IPlatformHandle.HandleDescriptor => "Perspex SurfaceView"; - - public void Resize(double width, double height) - { - if (ClientSize == new Size(width, height)) return; - ClientSize = new Size(width, height); - Resized(ClientSize); - } - - public Size ClientSize { get; set; } - IPlatformHandle ITopLevelImpl.Handle => this; - Action ITopLevelImpl.Activated { get; set; } - public Action Closed { get; set; } - public Action Deactivated { get; set; } - public Action Input { get; set; } - public Action Paint { get; set; } - public Action Resized { get; set; } - - public void Activate() - { - } - - public void SetInputRoot(IInputRoot inputRoot) - { - InputRoot = inputRoot; - } - - public Point PointToScreen(Point point) - { - return point; - } - - public void SetCursor(IPlatformHandle cursor) - { - } - - public Size MaxClientSize => _pointService.NativeToPerspex(new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels)); - - public View View => this; - - public void SetTitle(string title) - { - } - - void ITopLevelImpl.Show() - { - this.Visibility = ViewStates.Visible; - } - - public IDisposable ShowDialog() - { - throw new NotImplementedException(); - } - - public void Hide() - { - } - - public virtual Point GetPerspexPointFromEvent(MotionEvent e) => _pointService.NativeToPerspex(new Point(e.GetX(), e.GetY())); - - public override bool DispatchTouchEvent(MotionEvent e) - { - bool callBase; - bool? result = _touchHelper.DispatchTouchEvent(e, out callBase); - bool baseResult = callBase ? base.DispatchTouchEvent(e) : false; - - return result != null ? result.Value : baseResult; - } - - public override bool DispatchKeyEvent(KeyEvent e) - { - bool callBase; - bool? res = _keyboardHelper.DispatchKeyEvent(e, out callBase); - bool baseResult = callBase ? base.DispatchKeyEvent(e) : false; - - return res != null ? res.Value : baseResult; - } - - public void Invalidate(Rect rect) - { - this._renderHelper.Invalidate(rect); - } - - public virtual void PreRender(Canvas canvas, Rect rect) - { - } - - public virtual void Render(Canvas canvas, Rect rect) - { - Canvas = canvas; - Paint?.Invoke(rect); - } - - public virtual void PostRender(Canvas canvas, Rect rect) - { - _renderHelper.DrawDebugInfoToCanvas(canvas); - _touchHelper.DrawLastMousePoint(canvas); - } - - public AG.Canvas Canvas { get; private set; } - - public Dictionary VisualCaches => _renderHelper.VisualCaches; - - protected override void OnSizeChanged(int w, int h, int oldw, int oldh) - { - base.OnSizeChanged(w, h, oldw, oldh); - Resize(MaxClientSize.Width, MaxClientSize.Height); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/CanvasPlatform/WindowImpl.cs b/src/Android/Perspex.Android/Platform/CanvasPlatform/WindowImpl.cs deleted file mode 100644 index 6cb0ecc3ab..0000000000 --- a/src/Android/Perspex.Android/Platform/CanvasPlatform/WindowImpl.cs +++ /dev/null @@ -1,207 +0,0 @@ -using Android.Content; -using Android.Views; -using Perspex.Android.Platform.CanvasPlatform.Specific.Helpers; -using Perspex.Android.Platform.Specific; -using Perspex.Android.Platform.Specific.Helpers; -using Perspex.Input; -using Perspex.Input.Raw; -using Perspex.Platform; -using System; -using System.Collections.Generic; -using AG = Android.Graphics; - -namespace Perspex.Android.Platform.CanvasPlatform -{ - public class WindowImpl : View, - //GridLayout, //may be GridLayout can be better if int he future we want to embed native views or controls - IWindowImpl, IPlatformHandle, IAndroidCanvasView, IAndroidViewSupportRender, IDisposable - { - private IPointUnitService _pointService = PointUnitService.Instance; - - public ViewDrawType DrawType { get; } - - private AndroidViewRenderHelper _renderHelper; - protected AndroidKeyboardEventsHelper _keyboardHelper; - protected AndroidTouchEventsHelper _touchHelper; - - private bool _handleEvents; - - public bool HandleEvents - { - get { return _handleEvents; } - set - { - _handleEvents = value; - _keyboardHelper.HandleEvents = _handleEvents; - } - } - - internal static bool _debug = false; - - public WindowImpl(Context context) : base(context) - { - DrawType = AndroidPlatform.Instance.DefaultViewDrawType == ViewDrawType.SurfaceViewCanvasOnDraw ? ViewDrawType.CanvasOnDraw : AndroidPlatform.Instance.DefaultViewDrawType; - - _keyboardHelper = new AndroidKeyboardEventsHelper(this); - _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, GetPerspexPointFromEvent); - _renderHelper = AndroidViewRenderHelper.Create(this, DrawType); - - //LayerType = LayerType.Hardware; - //SetLayerType(LayerType.Hardware, null); - - ClientSize = MaxClientSize; - Resized = size => Invalidate(new Rect(size)); - this.Init(); - } - - public WindowImpl() : this(PerspexLocator.Current.GetService().Activity) - { - } - - protected virtual void Init() - { - HandleEvents = false; - - //if the background is not transparent nothing is visible!!! - //this is the case when inherit from GridLayout, not from View - //this.Background = new AG.Drawables.ColorDrawable(AG.Color.Transparent); - } - - public Rect Bounds { get; set; } - - public IInputRoot InputRoot { get; private set; } - IntPtr IPlatformHandle.Handle => Handle; - string IPlatformHandle.HandleDescriptor => "Perspex View"; - - public void Resize(double width, double height) - { - if (ClientSize == new Size(width, height)) return; - ClientSize = new Size(width, height); - Resized(ClientSize); - } - - public Size ClientSize { get; set; } - IPlatformHandle ITopLevelImpl.Handle => this; - Action ITopLevelImpl.Activated { get; set; } - public Action Closed { get; set; } - public Action Deactivated { get; set; } - public Action Input { get; set; } - public Action Paint { get; set; } - public Action Resized { get; set; } - - public void Activate() - { - } - - public void SetInputRoot(IInputRoot inputRoot) - { - InputRoot = inputRoot; - } - - public Point PointToScreen(Point point) - { - return point; - } - - public void SetCursor(IPlatformHandle cursor) - { - } - - public Size MaxClientSize => _pointService.NativeToPerspex(new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels)); - - public View View => this; - - public void SetTitle(string title) - { - } - - void ITopLevelImpl.Show() - { - this.Visibility = ViewStates.Visible; - } - - public IDisposable ShowDialog() - { - throw new NotImplementedException(); - } - - public void Hide() - { - this.Visibility = ViewStates.Invisible; - } - - public virtual Point GetPerspexPointFromEvent(MotionEvent e) => _pointService.NativeToPerspex(new Point(e.GetX(), e.GetY())); - - public override bool DispatchTouchEvent(MotionEvent e) - { - bool callBase; - bool? result = _touchHelper.DispatchTouchEvent(e, out callBase); - bool baseResult = callBase ? base.DispatchTouchEvent(e) : false; - - return result != null ? result.Value : baseResult; - } - - public override bool DispatchKeyEvent(KeyEvent e) - { - bool callBase; - bool? res = _keyboardHelper.DispatchKeyEvent(e, out callBase); - bool baseResult = callBase ? base.DispatchKeyEvent(e) : false; - - return res != null ? res.Value : baseResult; - } - - public void Invalidate(Rect rect) - { - this._renderHelper.Invalidate(rect); - } - - public AG.Canvas Canvas { get; private set; } - - public Dictionary VisualCaches - { - get - { - return _renderHelper.VisualCaches; - } - } - - protected TimeSpan _onDrawDuration; - - private DateTime _beginDraw; - - public virtual void PreRender(AG.Canvas canvas, Rect rect) - { - _beginDraw = DateTime.Now; - } - - public virtual void Render(AG.Canvas canvas, Rect rect) - { - Canvas = canvas; - Paint?.Invoke(rect); - } - - public virtual void PostRender(AG.Canvas canvas, Rect rect) - { - _renderHelper.DrawDebugInfoToCanvas(canvas); - _touchHelper.DrawLastMousePoint(canvas); - } - - protected override void OnDraw(AG.Canvas canvas) - { - _renderHelper.OnDraw(canvas); - } - - void IDisposable.Dispose() - { - _renderHelper.Dispose(); - _touchHelper.Dispose(); - _keyboardHelper.Dispose(); - } - - protected override void OnSizeChanged(int w, int h, int oldw, int oldh) - { - base.OnSizeChanged(w, h, oldw, oldh); - Resize(MaxClientSize.Width, MaxClientSize.Height); - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs index 8facdb0683..b7125a56ed 100644 --- a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs @@ -9,7 +9,6 @@ using Perspex.Input.Raw; using Perspex.Platform; using Perspex.Skia.Android; using System; -using System.Collections.Generic; namespace Perspex.Android.Platform.SkiaPlatform { @@ -146,30 +145,10 @@ namespace Perspex.Android.Platform.SkiaPlatform return res != null ? res.Value : baseResult; } - - private Queue _avgDrawQueue = new Queue(); - + protected override void Draw() { - DateTime begin = DateTime.Now; - Paint?.Invoke(new Rect(new Point(0, 0), ClientSize)); - - TimeSpan duration = DateTime.Now - begin; - - if (AndroidPlatform.Instance.DrawDebugInfo) - { - //draw some basic debug info about rendering - //we can't create drawing context so push some info to std out - //double ms = duration.TotalMilliseconds; - //_avgDrawQueue.Enqueue(ms); - //if (_avgDrawQueue.Count > 50) _avgDrawQueue.Dequeue(); - - //double msAvg = _avgDrawQueue.Average(); - - //string text = $"DrawType={AndroidPlatform.Instance.DefaultViewDrawType}, OnDraw={ms.ToString("0.00")}, aOnDraw={msAvg.ToString("0.00")}"; - //Log.Debug("render", text); - } } } } \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/Specific/CommonUITimer.cs b/src/Android/Perspex.Android/Platform/Specific/CommonUITimer.cs deleted file mode 100644 index e62e9294f9..0000000000 --- a/src/Android/Perspex.Android/Platform/Specific/CommonUITimer.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Perspex.Android.Platform.Specific -{ - public class CommonUITimer : IDisposable - { - private System.Timers.Timer _timer; - private TimeSpan _interval; - private Dictionary _actions = new Dictionary(); - - public CommonUITimer(TimeSpan interval) - { - _timer = new System.Timers.Timer(interval.TotalMilliseconds); - _interval = interval; - _timer.Elapsed += _timer_Elapsed; - _timer.Start(); - } - - private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - DateTime now = DateTime.Now; - foreach (var kvp in _actions) - { - if ((now - kvp.Value) >= _interval) - { - kvp.Key(); - } - } - } - - public void AddAction(Action action) - { - _actions[action] = DateTime.Now; - } - - public void Dispose() - { - _timer.Elapsed -= _timer_Elapsed; - _timer?.Stop(); - } - - public void RemoveAction(Action action) - { - _actions.Remove(action); - } - - public int ActiveActionsCount => _actions.Count; - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs b/src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs index 96a7c2cadb..4b7dcff826 100644 --- a/src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs +++ b/src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs @@ -1,6 +1,5 @@ using Android.Graphics; using Android.Views; -using Perspex.Android.Platform.CanvasPlatform; using Perspex.Input; using Perspex.Input.Raw; using Perspex.Media; @@ -128,33 +127,6 @@ namespace Perspex.Android.Platform.Specific.Helpers private Paint _paint; - public void DrawLastMousePoint(DrawingContext context) - { - if (!AndroidPlatform.Instance.DrawDebugInfo) return; - - double w = AndroidPlatform.Instance.DoubleClickSize.Width; - context.FillRectangle(Brushes.Red, new Rect(_point.X - w / 2, _point.Y - w / 2, w, w)); - } - - public void DrawLastMousePoint(Canvas canvas) - { - if (!AndroidPlatform.Instance.DrawDebugInfo) return; - - if (_paint == null) - { - _paint = new Paint() { Color = global::Android.Graphics.Color.Red, }; - _paint.SetStyle(Paint.Style.Fill); - } - - if (AndroidPlatform.Instance.DefaultViewDrawType != ViewDrawType.Skia) - { - canvas.DrawCircle(PointUnitService.Instance.PerspexToNativeXF(_point.X), - PointUnitService.Instance.PerspexToNativeYF(_point.Y), - (float)AndroidPlatform.Instance.DoubleClickSize.Width, - _paint); - } - } - public void Dispose() { HandleEvents = false; diff --git a/src/Android/Perspex.Android/Platform/Specific/Helpers/ViewDrawType.cs b/src/Android/Perspex.Android/Platform/Specific/Helpers/ViewDrawType.cs deleted file mode 100644 index fb19de2b00..0000000000 --- a/src/Android/Perspex.Android/Platform/Specific/Helpers/ViewDrawType.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using Android.App; -using Android.Content; -using Android.OS; -using Android.Runtime; -using Android.Views; -using Android.Widget; - -namespace Perspex.Android.Platform.Specific.Helpers -{ - public enum ViewDrawType - { - Skia, - CanvasOnDraw, - BitmapOnPreDraw, - BitmapBackgroundRender, - SurfaceViewCanvasOnDraw - } -} \ No newline at end of file diff --git a/src/Android/Perspex.Android/Platform/Specific/PerspexActivity.cs b/src/Android/Perspex.Android/Platform/Specific/PerspexActivity.cs index 9843a9d82d..40ecc259cf 100644 --- a/src/Android/Perspex.Android/Platform/Specific/PerspexActivity.cs +++ b/src/Android/Perspex.Android/Platform/Specific/PerspexActivity.cs @@ -1,3 +1,4 @@ +using System; using Android.App; using Android.OS; using Android.Views; @@ -9,6 +10,11 @@ namespace Perspex.Android.Platform.Specific { private IAndroidView _contentView; + public PerspexActivity(Type applicationType) + { + AndroidPlatform.Instance.Init(applicationType); + } + public Activity Activity => this; public IAndroidView ContentView diff --git a/src/Android/Perspex.AndroidTestApplication/App.cs b/src/Android/Perspex.AndroidTestApplication/App.cs deleted file mode 100644 index e1d5182b50..0000000000 --- a/src/Android/Perspex.AndroidTestApplication/App.cs +++ /dev/null @@ -1,372 +0,0 @@ -using Perspex.Android; -using Perspex.Controls; -using Perspex.Controls.Shapes; -using Perspex.Interactivity; -using Perspex.Layout; -using Perspex.Media; -using Perspex.Media.Imaging; -using Perspex.Platform; -using Perspex.Themes.Default; -using System; - -namespace Perspex.AndroidTestApplication -{ - public class App : Application - { - public App() - { - RegisterServices(); - InitializePlatform(); - - Styles = new DefaultTheme(); - } - - protected void InitializePlatform() - { - AndroidPlatform.Initialize(); - //not needed already default assembly is set to Activity that inherits PerspexActivity - //AndroidPlatform.Instance.SetDefaultAssetAssembly(typeof(App).Assembly); - } - - public Window BuildSimpleTextUI() - { - var window = new Window - { - Title = "Perspex Test Application", - Background = Brushes.Green, - Content = new Grid - { - VerticalAlignment = VerticalAlignment.Top, - HorizontalAlignment = HorizontalAlignment.Left, - Margin = new Thickness(10, 10, 0, 0), - Children = new Controls.Controls - { - new TextBlock - { - Foreground = Brushes.GhostWhite, - Background = Brushes.BlueViolet, - VerticalAlignment = VerticalAlignment.Top, - HorizontalAlignment = HorizontalAlignment.Left, - Text = - "Hello! This is a test of text wrapping and me actually getting something to render for the first time in life. Im and happy to say this was by no means all me. I want to thank everyone who helped me this far.", - FontSize = 80, - Margin = new Thickness(10), - TextWrapping = TextWrapping.Wrap - } - } - } - }; - - return window; - } - - public Window BuildStackPanelUI() - { - var window = new Window - { - Title = "Perspex Test Application", - Background = Brushes.Green, - Content = new Grid - { - VerticalAlignment = VerticalAlignment.Top, - HorizontalAlignment = HorizontalAlignment.Left, - Margin = new Thickness(10, 10, 0, 0), - Children = new Controls.Controls - { - new StackPanel - { - Orientation = Orientation.Horizontal, - [Grid.RowProperty] = 1, - [Grid.ColumnSpanProperty] = 2, - // Background = SolidColorBrush.Parse("#000000"), - Children = new Controls.Controls - { - new Button - { - Content = "Button 1", - Width = 100, - Foreground = Brushes.Blue, - Margin = new Thickness(5) - }, - new Button - { - Content = "Button 2", - Width = 100, - Margin = new Thickness(5) - }, - new Button - { - Content = "Button 3", - Width = 100, - Margin = new Thickness(5) - } - } - } - } - } - }; - - return window; - } - - public Window BuildGridWithSomeButtonsAndStuff() - { - var buttonToClick = new Button - { - Content = "Tap Me", - Width = 200, - Foreground = Brushes.White, - Margin = new Thickness(5), - Background = Brushes.Blue, - FontSize = 50 - }; - - var clickCount = 0; - buttonToClick.Click += (object sender, RoutedEventArgs e) => - { - Console.WriteLine("You clicked it :)"); - buttonToClick.Content = $"Tap x{clickCount}"; - clickCount++; - }; - - var window = new Window - { - Title = "Perspex Test Application", - Background = Brushes.DarkTurquoise, - Content = new Grid - { - Margin = new Thickness(0, 0, 0, 0), // skip the status bar area on iOS - ColumnDefinitions = new ColumnDefinitions - { - new ColumnDefinition(1, GridUnitType.Star), - new ColumnDefinition(1, GridUnitType.Star) - }, - RowDefinitions = new RowDefinitions - { - new RowDefinition(80, GridUnitType.Pixel), - new RowDefinition(160, GridUnitType.Pixel), - new RowDefinition(1, GridUnitType.Star), - new RowDefinition(1, GridUnitType.Star) - }, - Children = new Controls.Controls - { - new TextBlock - { - [Grid.RowProperty] = 0, - [Grid.ColumnSpanProperty] = 2, - Text = "Welcome to Perspex on Android !!!", - Foreground = Brushes.SteelBlue, - Background = Brushes.White, - FontSize = 50, - Margin = new Thickness(5, 7, 5, 5), - TextAlignment = TextAlignment.Left - }, -//// - new StackPanel - { - Orientation = Orientation.Horizontal, - [Grid.RowProperty] = 1, - [Grid.ColumnSpanProperty] = 2, - Background = Brush.Parse("#000000"), - Children = new Controls.Controls - { - buttonToClick, - new Button - { - Content = "Button 2", - Width = 250, - FontSize = 50, - Margin = new Thickness(5) - }, - new Button - { - Content = "Button 3", - Width = 250, - FontSize = 50, - Margin = new Thickness(5) - } - } - }, -//// - new Image - { - [Grid.RowProperty] = 2, - [Grid.ColumnProperty] = 0, - Margin = new Thickness(20), - // Source = new Bitmap("github_icon.png"), - Opacity = 0.4 - }, -//// - new Ellipse - { - [Grid.RowProperty] = 3, - [Grid.ColumnProperty] = 0, - Margin = new Thickness(20), - Fill = Brushes.Blue - }, -//// - new TextBlock - { - [Grid.RowProperty] = 2, - [Grid.ColumnProperty] = 1, - Text = - "How does this look? Is this text going to wrap and then look nice within the bounds of this widget? If not I will be extremely disappointed!\n\nWill we start a new paragraph here? If not there will be hell to pay!!!!", - Foreground = Brushes.Purple, - Background = Brushes.Transparent, - FontSize = 28, - Margin = new Thickness(10, 30, 10, 10) - }, - new Path - { - Data = - StreamGeometry.Parse( - "M 50,50 l 15,0 l 5,-15 l 5,15 l 15,0 l -10,10 l 4,15 l -15,-9 l -15,9 l 7,-15 Z"), - [Grid.RowProperty] = 3, - [Grid.ColumnProperty] = 1, - Margin = new Thickness(20), - Fill = Brushes.White, - Stroke = Brushes.Blue, - StrokeThickness = 4 - } - } - } - }; - - return window; - } - - public Window BuildGridWithSomeButtonsAndStuff2() - { - var buttonToClick = new Button - { - Content = "Tap Me", - Width = 200, - Foreground = Brushes.White, - Margin = new Thickness(5), - Background = Brushes.Blue, - FontSize = 50 - }; - - var clickCount = 0; - buttonToClick.Click += (object sender, RoutedEventArgs e) => - { - Console.WriteLine("You clicked it :)"); - buttonToClick.Content = $"Tap x{clickCount}"; - clickCount++; - }; - - var window = new Window - { - Title = "Perspex Test Application", - Background = Brushes.DarkTurquoise, - Content = new Grid - { - Margin = new Thickness(0, 50, 0, 0), // skip the status bar area on iOS - ColumnDefinitions = new ColumnDefinitions - { - new ColumnDefinition(1, GridUnitType.Star), - new ColumnDefinition(1, GridUnitType.Star) - }, - RowDefinitions = new RowDefinitions - { - new RowDefinition(80, GridUnitType.Pixel), - new RowDefinition(160, GridUnitType.Pixel), - new RowDefinition(1, GridUnitType.Star), - new RowDefinition(1, GridUnitType.Star) - }, - Children = new Controls.Controls - { - new TextBox - { - [Grid.RowProperty] = 0, - [Grid.ColumnSpanProperty] = 2, - Text = "Welcome to Perspex on Android !!!", - Foreground = Brushes.SteelBlue, - Background = Brushes.White, - FontSize = 50, - //Margin = new Thickness(5, 7, 5, 5), - Margin = new Thickness(5, 7, 5, 5), - //VerticalAlignment = VerticalAlignment.Bottom - //TextAlignment = TextAlignment.Left - }, -//// - new StackPanel - { - Orientation = Orientation.Horizontal, - [Grid.RowProperty] = 1, - [Grid.ColumnSpanProperty] = 2, - Background = Brush.Parse("#000000"), - Children = new Controls.Controls - { - buttonToClick, - new Button - { - Content = "Button 2", - Width = 250, - FontSize = 50, - Margin = new Thickness(5) - }, - new Button - { - Content = "Button 3", - Width = 250, - FontSize = 50, - Margin = new Thickness(5) - } - } - }, -//// - new Image - { - [Grid.RowProperty] = 2, - [Grid.ColumnProperty] = 0, - Margin = new Thickness(20), - //Stretch=Stretch.Uniform, - Width=400, - Height=400, - // Source = new Bitmap("github_icon.png"), - Source = new Bitmap(PerspexLocator.Current.GetService().Open(new Uri("res://component/Perspex Test Application/Perspex.AndroidTestApplication.github_icon.png"))), - Opacity = 0.4 - }, -//// - new Ellipse - { - [Grid.RowProperty] = 3, - [Grid.ColumnProperty] = 0, - Margin = new Thickness(20), - Fill = Brushes.Blue, - //Stroke = Brushes.Red, - //StrokeThickness = 4 - }, -//// - new TextBlock - { - [Grid.RowProperty] = 2, - [Grid.ColumnProperty] = 1, - Text = - "How does this look? Is this text going to wrap and then look nice within the bounds of this widget? If not I will be extremely disappointed!\n\nWill we start a new paragraph here? If not there will be hell to pay!!!!", - Foreground = Brushes.Purple, - Background = Brushes.Transparent, - FontSize = 28, - Margin = new Thickness(10, 30, 10, 10) - }, - new Path - { - Data = - StreamGeometry.Parse( - "M 50,50 l 15,0 l 5,-15 l 5,15 l 15,0 l -10,10 l 4,15 l -15,-9 l -15,9 l 7,-15 Z"), - [Grid.RowProperty] = 3, - [Grid.ColumnProperty] = 1, - Margin = new Thickness(20), - Fill = Brushes.White, - Stroke = Brushes.Blue, - StrokeThickness = 4 - } - } - } - }; - - return window; - } - } -} \ No newline at end of file diff --git a/src/Android/Perspex.AndroidTestApplication/GettingStarted.Xamarin b/src/Android/Perspex.AndroidTestApplication/GettingStarted.Xamarin deleted file mode 100644 index e9d4f6a411..0000000000 --- a/src/Android/Perspex.AndroidTestApplication/GettingStarted.Xamarin +++ /dev/null @@ -1,4 +0,0 @@ - - GS\Android\CS\AndroidApp\GettingStarted.html - false - \ No newline at end of file diff --git a/src/Android/Perspex.AndroidTestApplication/MainActivity.cs b/src/Android/Perspex.AndroidTestApplication/MainActivity.cs index 9d98b23cab..faf5621210 100644 --- a/src/Android/Perspex.AndroidTestApplication/MainActivity.cs +++ b/src/Android/Perspex.AndroidTestApplication/MainActivity.cs @@ -6,6 +6,7 @@ using Perspex.Android.Platform.Specific; using Perspex.Android.Platform.Specific.Helpers; using Perspex.Controls.Platform; using Perspex.Platform; +using TestApplication; namespace Perspex.AndroidTestApplication { @@ -16,57 +17,28 @@ namespace Perspex.AndroidTestApplication ScreenOrientation = ScreenOrientation.Landscape*/)] public class MainBaseActivity : PerspexActivity { - protected override void OnCreate(Bundle savedInstanceState) + public MainBaseActivity() : base(typeof (App)) { - base.OnCreate(savedInstanceState); - //set some parameters to android platform - AndroidPlatform.Instance.DrawDebugInfo = true; - //skia is the default rendering method on android so no need to set it - AndroidPlatform.Instance.DefaultViewDrawType = ViewDrawType.Skia; - //AndroidPlatform.Instance.DefaultViewDrawType = ViewDrawType.BitmapOnPreDraw; - //AndroidPlatform.Instance.DefaultViewDrawType = ViewDrawType.CanvasOnDraw; - //AndroidPlatform.Instance.DefaultViewDrawType = ViewDrawType.BitmapBackgroundRender; - //AndroidPlatform.Instance.DefaultViewDrawType = ViewDrawType.SurfaceViewCanvasOnDraw; - //AndroidPlatform.Instance.DefaultPointUnit = Android.Platform.CanvasPlatform.PointUnit.DP; - //AndroidPlatform.Instance.DefaultPointUnit = Android.Platform.CanvasPlatform.PointUnit.Pixel; + } - //60 fps animation are causing user interface in animations to stop responding - AndroidPlatform.Instance.OverrideAnimateFramesPerSecond = 16; + protected override void OnCreate(Bundle savedInstanceState) + { + base.OnCreate(savedInstanceState); App app; if (Perspex.Application.Current != null) app = (App)Perspex.Application.Current; else app = new App(); + - if (AndroidPlatform.Instance.DefaultPointUnit == Android.Platform.CanvasPlatform.PointUnit.DP && - AndroidPlatform.Instance.DefaultViewDrawType == ViewDrawType.Skia) - { - double scale = Resources.DisplayMetrics.ScaledDensity; - //make it DiP in skia - PerspexLocator.Current.GetService().LayoutScalingFactor = scale; - PerspexLocator.Current.GetService().RenderScalingFactor = scale; - } - - var window = TestUI.TestUIBuilder.BuildTestUI(); - //var window = BuildPlatforSetup(); + MainWindow.RootNamespace = "Perspex.AndroidTestApplication"; + var window = MainWindow.Create(); window.Show(); app.Run(window); } - - public static void StartAppFromSetup() - { - PerspexLocator.Current.GetService().Dispose(); - - AndroidPlatform.Instance.RegisterViewDrawType(); - AndroidPlatform.Instance.RegisterViewPointUnits(); - - var window = TestUI.TestUIBuilder.BuildTestUI(); - - window.Show(); - Perspex.Application.Current.Run(window); - } + } } \ No newline at end of file diff --git a/src/Android/Perspex.AndroidTestApplication/Perspex.AndroidTestApplication.csproj b/src/Android/Perspex.AndroidTestApplication/Perspex.AndroidTestApplication.csproj index ecdb79d773..11d757083d 100644 --- a/src/Android/Perspex.AndroidTestApplication/Perspex.AndroidTestApplication.csproj +++ b/src/Android/Perspex.AndroidTestApplication/Perspex.AndroidTestApplication.csproj @@ -106,22 +106,15 @@ - - - - - - - Designer @@ -199,16 +192,7 @@ Perspex.Skia.Android - - - Always - - - - - PreserveNewest - - + + \ 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 index 2916c4059e..2146b7a9e9 100644 --- a/src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj +++ b/src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj @@ -15,7 +15,7 @@ Resources\Resource.Designer.cs Off True - v6.0 + v5.1 true diff --git a/src/Skia/Perspex.Skia.Android/SkiaView.cs b/src/Skia/Perspex.Skia.Android/SkiaView.cs index d78ffdbcef..fbd27a8ef7 100644 --- a/src/Skia/Perspex.Skia.Android/SkiaView.cs +++ b/src/Skia/Perspex.Skia.Android/SkiaView.cs @@ -20,12 +20,15 @@ namespace Perspex.Skia.Android { private readonly Activity _context; bool _invalidateQueued; - object _lock = new object(); + readonly object _lock = new object(); + private readonly Handler _handler; + public SkiaView(Activity context) : base(context) { _context = context; SkiaPlatform.Initialize(); Holder.AddCallback(this); + _handler = new Handler(context.MainLooper); } public override void Invalidate() @@ -34,13 +37,20 @@ namespace Perspex.Skia.Android { if(_invalidateQueued) return; - _context.RunOnUiThread(() => + _handler.Post(() => { lock (_lock) { _invalidateQueued = false; } - Draw(); + try + { + Draw(); + } + catch (Exception e) + { + Log.WriteLine(LogPriority.Error, "Perspex", e.ToString()); + } }); } }