From c446aaf5a6a364d26a32d9c92ba126d58c50ca41 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 28 Jan 2017 23:22:53 +0300 Subject: [PATCH] Removed IWindowImpl which was a lie, removed initialization hack, fixed rendering --- .../ControlCatalog.Android.csproj | 7 +- .../ControlCatalog.Android/MainActivity.cs | 24 ++---- .../Avalonia.Android/AndroidPlatform.cs | 25 +++--- .../AndroidThreadingInterface.cs | 12 ++- .../Avalonia.Android/Avalonia.Android.csproj | 7 +- .../Avalonia.Android/AvaloniaActivity.cs | 50 ++++++++++++ src/Android/Avalonia.Android/AvaloniaView.cs | 59 ++++++++++++++ .../Platform/SkiaPlatform/MainWindowImpl.cs | 44 ----------- .../{WindowImpl.cs => TopLevelImpl.cs} | 24 ++---- .../Platform/Specific/AvaloniaActivity.cs | 60 --------------- .../Helpers/AndroidKeyboardEventsHelper.cs | 2 +- .../Helpers/AndroidTouchEventsHelper.cs | 2 +- .../Platform/Specific/IAndroidActivity.cs | 12 --- .../Avalonia.AndroidTestApplication.csproj | 12 +-- .../MainActivity.cs | 32 ++------ .../Avalonia.Skia.Android.csproj | 1 + .../Avalonia.Skia.Android/NativeMethods.cs | 71 +++++++++++++++++ .../Avalonia.Skia.Android/RenderTarget.cs | 77 +++++++------------ src/Skia/Avalonia.Skia.Android/SkiaView.cs | 4 +- 19 files changed, 271 insertions(+), 254 deletions(-) create mode 100644 src/Android/Avalonia.Android/AvaloniaActivity.cs create mode 100644 src/Android/Avalonia.Android/AvaloniaView.cs delete mode 100644 src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs rename src/Android/Avalonia.Android/Platform/SkiaPlatform/{WindowImpl.cs => TopLevelImpl.cs} (86%) delete mode 100644 src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs delete mode 100644 src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs create mode 100644 src/Skia/Avalonia.Skia.Android/NativeMethods.cs diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 5b39aa3dfb..7dd09df73c 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -29,12 +29,15 @@ 4 True None - False + True False False - armeabi,armeabi-v7a,x86 + armeabi;armeabi-v7a;x86 Xamarin False + False + False + False pdbonly diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index 3f357b0e70..157609088f 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/samples/ControlCatalog.Android/MainActivity.cs @@ -1,9 +1,8 @@ using System; using Android.App; - using Android.OS; using Android.Content.PM; -using Avalonia.Android.Platform.Specific; +using Avalonia.Android; using Avalonia.Controls; using Avalonia.Controls.Templates; using Avalonia.Markup.Xaml; @@ -17,29 +16,16 @@ namespace ControlCatalog.Android [Activity(Label = "ControlCatalog.Android", MainLauncher = true, Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)] public class MainActivity : AvaloniaActivity { - public MainActivity() : base(typeof (App)) - { - - } - protected override void OnCreate(Bundle savedInstanceState) { - base.OnCreate(savedInstanceState); - - App app; - if (Avalonia.Application.Current != null) - app = (App)Avalonia.Application.Current; - else + if (Avalonia.Application.Current == null) { - app = new App(); - AppBuilder.Configure(app) + AppBuilder.Configure(new App()) .UseAndroid() - .UseSkia() .SetupWithoutStarting(); + Content = new MainView(); } - - var mainWindow = new MainWindow(); - app.Run(mainWindow); + base.OnCreate(savedInstanceState); } } } diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index afaa314e6c..5b3170a0c7 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/src/Android/Avalonia.Android/AndroidPlatform.cs @@ -1,5 +1,8 @@ using System; using System.IO; +using System.Linq; +using Android.Content; +using Android.Views; using Avalonia.Android.Platform; using Avalonia.Android.Platform.Input; using Avalonia.Android.Platform.SkiaPlatform; @@ -8,6 +11,7 @@ using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Platform; +using Avalonia.Rendering; using Avalonia.Shared.PlatformSupport; using Avalonia.Skia; @@ -17,7 +21,8 @@ namespace Avalonia { public static T UseAndroid(this T builder) where T : AppBuilderBase, new() { - builder.UseWindowingSubsystem(Android.AndroidPlatform.Initialize, "Android"); + builder.UseWindowingSubsystem(() => Android.AndroidPlatform.Initialize(builder.Instance), "Android"); + builder.UseSkia(); return builder; } } @@ -25,7 +30,7 @@ namespace Avalonia namespace Avalonia.Android { - public class AndroidPlatform : IPlatformSettings, IWindowingPlatform + class AndroidPlatform : IPlatformSettings, IWindowingPlatform { public static readonly AndroidPlatform Instance = new AndroidPlatform(); public Size DoubleClickSize => new Size(4, 4); @@ -40,7 +45,7 @@ namespace Avalonia.Android _scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity; } - public static void Initialize() + public static void Initialize(Avalonia.Application app) { AvaloniaLocator.CurrentMutable .Bind().ToTransient() @@ -51,24 +56,22 @@ namespace Avalonia.Android .Bind().ToConstant(new AndroidThreadingInterface()) .Bind().ToTransient() .Bind().ToConstant(Instance) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(new DefaultRenderLoop(60)) - SkiaPlatform.Initialize(); - } + .Bind().ToConstant(new AssetLoader(app.GetType().Assembly)); - public void Init(Type applicationType) - { - StandardRuntimePlatformServices.Register(applicationType.Assembly); + SkiaPlatform.Initialize(); } public IWindowImpl CreateWindow() { - return new WindowImpl(); + throw new NotSupportedException(); } public IEmbeddableWindowImpl CreateEmbeddableWindow() { - throw new NotImplementedException(); + throw new NotSupportedException(); } public IPopupImpl CreatePopup() diff --git a/src/Android/Avalonia.Android/AndroidThreadingInterface.cs b/src/Android/Avalonia.Android/AndroidThreadingInterface.cs index b4059e3114..6327be12a5 100644 --- a/src/Android/Avalonia.Android/AndroidThreadingInterface.cs +++ b/src/Android/Avalonia.Android/AndroidThreadingInterface.cs @@ -51,10 +51,16 @@ namespace Avalonia.Android scheduled = true; EnsureInvokeOnMainThread(() => { - tick(); - lock (l) + try { - scheduled = false; + tick(); + } + finally + { + lock (l) + { + scheduled = false; + } } }); } diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 654cb13678..e84146ffb3 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -63,16 +63,15 @@ + + - - + - - diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs new file mode 100644 index 0000000000..a9b04c882b --- /dev/null +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -0,0 +1,50 @@ +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 Avalonia.Android +{ + public abstract class AvaloniaActivity : Activity + { + AvaloniaView _view; + object _content; + + protected override void OnCreate(Bundle savedInstanceState) + { + RequestWindowFeature(WindowFeatures.NoTitle); + _view = new AvaloniaView(this); + if(_content != null) + _view.Content = _content; + SetContentView(_view); + TakeKeyEvents(true); + base.OnCreate(savedInstanceState); + } + + public object Content + { + get + { + return _content; + } + set + { + _content = value; + if (_view != null) + _view.Content = value; + } + } + + public override bool DispatchKeyEvent(KeyEvent e) + { + return _view.DispatchKeyEvent(e); + } + } +} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs new file mode 100644 index 0000000000..71eea14a1d --- /dev/null +++ b/src/Android/Avalonia.Android/AvaloniaView.cs @@ -0,0 +1,59 @@ +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; +using Avalonia.Android.Platform.SkiaPlatform; +using Avalonia.Controls.Embedding; +using Avalonia.Platform; + +namespace Avalonia.Android +{ + public class AvaloniaView : FrameLayout + { + private readonly EmbeddableControlRoot _root; + private readonly ViewImpl _view; + + public AvaloniaView(Context context) : base(context) + { + _view = new ViewImpl(context); + AddView(_view); + _root = new EmbeddableControlRoot(_view); + _root.Prepare(); + } + + public object Content + { + get { return _root.Content; } + set { _root.Content = value; } + } + + public override bool DispatchKeyEvent(KeyEvent e) + { + return _view.DispatchKeyEvent(e); + } + + class ViewImpl : TopLevelImpl, IEmbeddableWindowImpl + { + public event Action LostFocus; + + public ViewImpl(Context context) : base(context) + { + Focusable = true; + FocusChange += ViewImpl_FocusChange; + } + + private void ViewImpl_FocusChange(object sender, FocusChangeEventArgs e) + { + if(!e.HasFocus) + LostFocus?.Invoke(); + } + } + } +} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs deleted file mode 100644 index 690c509b53..0000000000 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Android.Views; -using Avalonia.Android.Platform.Specific; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Platform; - -namespace Avalonia.Android.Platform.SkiaPlatform -{ - public class MainWindowImpl : - WindowImpl - , IWindowImpl - { - public MainWindowImpl() - { - } - - public new WindowState WindowState - { - get { return WindowState.Normal; } - set { } - } - - protected override void Init() - { - base.Init(); - - HandleEvents = true; - _keyboardHelper.ActivateAutoShowKeybord(); - } - - void ITopLevelImpl.Show() - { - (Parent as ViewGroup)?.RemoveAllViews(); - AvaloniaLocator.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/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs similarity index 86% rename from src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs rename to src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 17b1cfba0a..1687432bb3 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -14,25 +14,21 @@ using Avalonia.Controls; namespace Avalonia.Android.Platform.SkiaPlatform { - public class WindowImpl : SkiaView, IAndroidView, IWindowImpl, ISurfaceHolderCallback + class TopLevelImpl : SkiaView, IAndroidView, ITopLevelImpl, ISurfaceHolderCallback { - protected AndroidKeyboardEventsHelper _keyboardHelper; + protected AndroidKeyboardEventsHelper _keyboardHelper; - private AndroidTouchEventsHelper _touchHelper; + private AndroidTouchEventsHelper _touchHelper; - public WindowImpl(Context context) : base((Activity)context) + public TopLevelImpl(Context context) : base(context) { - _keyboardHelper = new AndroidKeyboardEventsHelper(this); - _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p)); + _keyboardHelper = new AndroidKeyboardEventsHelper(this); + _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p)); MaxClientSize = new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels); ClientSize = MaxClientSize; - Init(); - } - - public WindowImpl() : this(AvaloniaLocator.Current.GetService().Activity) - { } + void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) { @@ -46,11 +42,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform base.SurfaceChanged(holder, format, width, height); } - - protected virtual void Init() - { - } - + private bool _handleEvents; public bool HandleEvents diff --git a/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs b/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs deleted file mode 100644 index 4ccff10455..0000000000 --- a/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using Android.App; -using Android.OS; -using Android.Views; -using Android.Widget; - -namespace Avalonia.Android.Platform.Specific -{ - public class AvaloniaActivity : Activity, IAndroidActivity - { - private IAndroidView _contentView; - - public AvaloniaActivity(Type applicationType) - { - AndroidPlatform.Instance.Init(applicationType); - } - - public Activity Activity => this; - - public IAndroidView ContentView - { - get - { - return this._contentView; - } - - set - { - this._contentView = value; - var fl = new FrameLayout(this); - fl.AddView(this._contentView.View); - //this.SetContentView(value.View); - this.SetContentView(fl); - } - } - - protected override void OnCreate(Bundle savedInstanceState) - { - AvaloniaLocator.CurrentMutable.Bind().ToConstant(this); - RequestWindowFeature(WindowFeatures.NoTitle); - base.OnCreate(savedInstanceState); - } - - public override void SetContentView(View view) - { - base.SetContentView(view); - TakeKeyEvents(true); - } - - public override bool DispatchKeyEvent(KeyEvent e) - { - if (_contentView != null) - { - _contentView.View.DispatchKeyEvent(e); - } - - return base.DispatchKeyEvent(e); - } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index 17e1f62e8c..7bac0ff814 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs @@ -12,7 +12,7 @@ using System.ComponentModel; namespace Avalonia.Android.Platform.Specific.Helpers { - public class AndroidKeyboardEventsHelper : IDisposable where TView : View, IWindowImpl, IAndroidView + public class AndroidKeyboardEventsHelper : IDisposable where TView : View, ITopLevelImpl, IAndroidView { private TView _view; private IInputElement _lastFocusedElement; diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs index c6d1833d2d..a448044ee6 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs @@ -8,7 +8,7 @@ using System; namespace Avalonia.Android.Platform.Specific.Helpers { - public class AndroidTouchEventsHelper : IDisposable where TView : View, IWindowImpl, IAndroidView + public class AndroidTouchEventsHelper : IDisposable where TView : View, ITopLevelImpl, IAndroidView { private TView _view; public bool HandleEvents { get; set; } diff --git a/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs b/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs deleted file mode 100644 index b2a999d4be..0000000000 --- a/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Android.App; -using Android.Views; - -namespace Avalonia.Android.Platform.Specific -{ - public interface IAndroidActivity - { - Activity Activity { get; } - - IAndroidView ContentView { get; set; } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj index e004121323..ebe268adcf 100644 --- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj +++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj @@ -20,7 +20,7 @@ Properties\AndroidManifest.xml - true + True full false bin\Debug\ @@ -29,16 +29,16 @@ 4 True None - - False + True False False - armeabi,armeabi-v7a,x86 - - + armeabi;armeabi-v7a;x86 Xamarin False True + False + False + False pdbonly diff --git a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs index ff27e12f6e..7973ad72e5 100644 --- a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs +++ b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs @@ -2,7 +2,7 @@ using System; using Android.App; using Android.Content.PM; using Android.OS; -using Avalonia.Android.Platform.Specific; +using Avalonia.Android; using Avalonia.Controls; using Avalonia.Controls.Templates; using Avalonia.Markup.Xaml; @@ -17,36 +17,24 @@ namespace Avalonia.AndroidTestApplication Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance/*, ScreenOrientation = ScreenOrientation.Landscape*/)] - public class MainBaseActivity : AvaloniaActivity + public class MainBaseActivity : Activity { - public MainBaseActivity() : base(typeof (App)) - { - - } - protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); - - App app; - if (Avalonia.Application.Current != null) - app = (App)Avalonia.Application.Current; - else + if (Avalonia.Application.Current == null) { - app = new App(); - AppBuilder.Configure(app) + AppBuilder.Configure() .UseAndroid() - .UseSkia() .SetupWithoutStarting(); } - - app.Run(); + SetContentView(new AvaloniaView(this) { Content = App.CreateSimpleWindow() }); } } public class App : Application { - public void Run() + public override void Initialize() { Styles.Add(new DefaultTheme()); @@ -55,18 +43,14 @@ namespace Avalonia.AndroidTestApplication new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default")); Styles.Add(baseLight); - var wnd = App.CreateSimpleWindow(); - wnd.AttachDevTools(); - Run(wnd); } // This provides a simple UI tree for testing input handling, drawing, etc - public static Window CreateSimpleWindow() + public static ContentControl CreateSimpleWindow() { - Window window = new Window + ContentControl window = new ContentControl() { - Title = "Avalonia Test Application", Background = Brushes.Red, Content = new StackPanel { diff --git a/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj b/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj index fdde5553eb..35c7af454b 100644 --- a/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj +++ b/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj @@ -89,6 +89,7 @@ + diff --git a/src/Skia/Avalonia.Skia.Android/NativeMethods.cs b/src/Skia/Avalonia.Skia.Android/NativeMethods.cs new file mode 100644 index 0000000000..b9557c00c7 --- /dev/null +++ b/src/Skia/Avalonia.Skia.Android/NativeMethods.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; + +namespace Avalonia.Skia.Android +{ + static class NativeMethods + { + [DllImport("android")] + internal static extern IntPtr ANativeWindow_fromSurface(IntPtr jniEnv, IntPtr handle); + + [DllImport("android")] + internal static extern void ANativeWindow_release(IntPtr window); + [DllImport("android")] + internal static extern void ANativeWindow_unlockAndPost(IntPtr window); + + [DllImport("android")] + internal static extern int ANativeWindow_lock(IntPtr window, out ANativeWindow_Buffer outBuffer, ref ARect inOutDirtyBounds); + public enum AndroidPixelFormat + { + WINDOW_FORMAT_RGBA_8888 = 1, + WINDOW_FORMAT_RGBX_8888 = 2, + WINDOW_FORMAT_RGB_565 = 4, + } + + internal struct ARect + { + public int left; + public int top; + public int right; + public int bottom; + } + + + internal struct ANativeWindow_Buffer + { + // The number of pixels that are show horizontally. + public int width; + + // The number of pixels that are shown vertically. + public int height; + + // The number of *pixels* that a line in the buffer takes in + // memory. This may be >= width. + public int stride; + + // The format of the buffer. One of WINDOW_FORMAT_* + public AndroidPixelFormat format; + + // The actual bits. + public IntPtr bits; + + // Do not touch. + uint reserved1; + uint reserved2; + uint reserved3; + uint reserved4; + uint reserved5; + uint reserved6; + } + } +} \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android/RenderTarget.cs b/src/Skia/Avalonia.Skia.Android/RenderTarget.cs index 03ddf49851..2ee8d5a839 100644 --- a/src/Skia/Avalonia.Skia.Android/RenderTarget.cs +++ b/src/Skia/Avalonia.Skia.Android/RenderTarget.cs @@ -3,7 +3,9 @@ using Avalonia.Media; using Avalonia.Platform; using SkiaSharp; using Android.Graphics; +using Android.Runtime; using Android.Views; +using Avalonia.Skia.Android; namespace Avalonia.Skia { @@ -27,49 +29,38 @@ namespace Avalonia.Skia internal class WindowRenderTarget : RenderTarget { private readonly SurfaceView _surfaceView; - Bitmap _bitmap; - int Width { get; set; } - int Height { get; set; } + private IntPtr _window; public WindowRenderTarget(SurfaceView surfaceView) { _surfaceView = surfaceView; - FixSize(); } - private void FixSize() + private void PrepareForDraw() { - int width, height; - GetPlatformWindowSize(out width, out height); - if (Width == width && Height == height) - return; - - Width = width; - Height = height; - - if (Surface != null) - { - Surface.Dispose(); - } - - if (_bitmap != null) - { - _bitmap.Dispose(); - } - - _bitmap = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888); - Surface = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, _bitmap.LockPixels(), width * 4); - } - - private void GetPlatformWindowSize(out int w, out int h) - { - w = _surfaceView.Width; - h = _surfaceView.Height; + int width = _surfaceView.Width; + var height = _surfaceView.Height; + + _window = NativeMethods.ANativeWindow_fromSurface(JNIEnv.Handle, _surfaceView.Holder.Surface.Handle); + var buffer = new NativeMethods.ANativeWindow_Buffer(); + var rc = new NativeMethods.ARect() {right = width, bottom = height}; + NativeMethods.ANativeWindow_lock(_window, out buffer, ref rc); + + var colorType = buffer.format == NativeMethods.AndroidPixelFormat.WINDOW_FORMAT_RGB_565 + ? SKColorType.Rgb565 : SKImageInfo.PlatformColorType; + + var stride = buffer.stride * (colorType == SKColorType.Rgb565 ? 2 : 4); + + Surface = SKSurface.Create(buffer.width, buffer.height, colorType, + SKAlphaType.Premul, buffer.bits, stride); + + if (Surface == null) + throw new Exception("Unable to create Skia surface"); } public override DrawingContext CreateDrawingContext() { - FixSize(); + PrepareForDraw(); var canvas = Surface.Canvas; canvas.RestoreToCount(0); @@ -84,23 +75,11 @@ namespace Avalonia.Skia public void Present() { - Canvas canvas = null; - try - { - canvas = _surfaceView.Holder.LockCanvas(null); - _bitmap.UnlockPixels(); - canvas.DrawBitmap(_bitmap, 0, 0, null); - } - catch (Exception) - { - } - finally - { - if (canvas != null) - _surfaceView.Holder.UnlockCanvasAndPost(canvas); - } - - _bitmap.UnlockPixels(); + Surface?.Dispose(); + Surface = null; + NativeMethods.ANativeWindow_unlockAndPost(_window); + NativeMethods.ANativeWindow_release(_window); + _window = IntPtr.Zero; } } } diff --git a/src/Skia/Avalonia.Skia.Android/SkiaView.cs b/src/Skia/Avalonia.Skia.Android/SkiaView.cs index a45a80cf18..f69462f087 100644 --- a/src/Skia/Avalonia.Skia.Android/SkiaView.cs +++ b/src/Skia/Avalonia.Skia.Android/SkiaView.cs @@ -18,12 +18,12 @@ namespace Avalonia.Skia.Android { public abstract class SkiaView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle { - private readonly Activity _context; + private readonly Context _context; bool _invalidateQueued; readonly object _lock = new object(); private readonly Handler _handler; - public SkiaView(Activity context) : base(context) + public SkiaView(Context context) : base(context) { _context = context; Holder.AddCallback(this);