Browse Source

Merge branch 'master' into jmacato/missing-skia-api-lottie

pull/5683/head
Jumar Macato 6 years ago
committed by GitHub
parent
commit
2b0bbf2f1a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 22
      src/Android/Avalonia.Android/AndroidPlatform.cs
  2. 15
      src/Android/Avalonia.Android/AndroidThreadingInterface.cs
  3. 8
      src/Android/Avalonia.Android/AvaloniaActivity.cs
  4. 14
      src/Android/Avalonia.Android/Platform/Input/AndroidMouseDevice.cs
  5. 6
      src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
  6. 2
      src/Android/Avalonia.Android/Platform/SkiaPlatform/FramebufferManager.cs
  7. 2
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  8. 38
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  9. 91
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
  10. 11
      src/Android/Avalonia.Android/app.config
  11. 2
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

22
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -29,21 +29,12 @@ namespace Avalonia
namespace Avalonia.Android namespace Avalonia.Android
{ {
class AndroidPlatform : IPlatformSettings, IWindowingPlatform class AndroidPlatform : IPlatformSettings
{ {
public static readonly AndroidPlatform Instance = new AndroidPlatform(); public static readonly AndroidPlatform Instance = new AndroidPlatform();
public static AndroidPlatformOptions Options { get; private set; } public static AndroidPlatformOptions Options { get; private set; }
public Size DoubleClickSize => new Size(4, 4); public Size DoubleClickSize => new Size(4, 4);
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(200); public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(200);
public double RenderScalingFactor => _scalingFactor;
public double LayoutScalingFactor => _scalingFactor;
private readonly double _scalingFactor = 1;
public AndroidPlatform()
{
_scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity;
}
public static void Initialize(Type appType, AndroidPlatformOptions options) public static void Initialize(Type appType, AndroidPlatformOptions options)
{ {
@ -56,7 +47,6 @@ namespace Avalonia.Android
.Bind<IPlatformSettings>().ToConstant(Instance) .Bind<IPlatformSettings>().ToConstant(Instance)
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface()) .Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>() .Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(Instance)
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>() .Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer()) .Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop()) .Bind<IRenderLoop>().ToConstant(new RenderLoop())
@ -70,16 +60,6 @@ namespace Avalonia.Android
EglPlatformOpenGlInterface.TryInitialize(); EglPlatformOpenGlInterface.TryInitialize();
} }
} }
public IWindowImpl CreateWindow()
{
throw new NotSupportedException();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotSupportedException();
}
} }
public sealed class AndroidPlatformOptions public sealed class AndroidPlatformOptions

15
src/Android/Avalonia.Android/AndroidThreadingInterface.cs

@ -1,25 +1,26 @@
using System; using System;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Threading; using System.Threading;
using Android.OS; using Android.OS;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using App = Android.App.Application;
namespace Avalonia.Android namespace Avalonia.Android
{ {
class AndroidThreadingInterface : IPlatformThreadingInterface internal sealed class AndroidThreadingInterface : IPlatformThreadingInterface
{ {
private Handler _handler; private Handler _handler;
public AndroidThreadingInterface() public AndroidThreadingInterface()
{ {
_handler = new Handler(global::Android.App.Application.Context.MainLooper); _handler = new Handler(App.Context.MainLooper);
} }
public void RunLoop(CancellationToken cancellationToken) public void RunLoop(CancellationToken cancellationToken) => throw new NotSupportedException();
{
return;
}
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick) public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
{ {
@ -57,7 +58,7 @@ namespace Avalonia.Android
}); });
} }
}, null, TimeSpan.Zero, interval); }, null, TimeSpan.Zero, interval);
return Disposable.Create(() => return Disposable.Create(() =>
{ {
lock (l) lock (l)

8
src/Android/Avalonia.Android/AvaloniaActivity.cs

@ -1,4 +1,3 @@
using Android.App; using Android.App;
using Android.OS; using Android.OS;
using Android.Views; using Android.Views;
@ -7,7 +6,6 @@ namespace Avalonia.Android
{ {
public abstract class AvaloniaActivity : Activity public abstract class AvaloniaActivity : Activity
{ {
internal AvaloniaView View; internal AvaloniaView View;
object _content; object _content;
@ -35,9 +33,7 @@ namespace Avalonia.Android
} }
} }
public override bool DispatchKeyEvent(KeyEvent e) public override bool DispatchKeyEvent(KeyEvent e) =>
{ View.DispatchKeyEvent(e) ? true : base.DispatchKeyEvent(e);
return View.DispatchKeyEvent(e);
}
} }
} }

14
src/Android/Avalonia.Android/Platform/Input/AndroidMouseDevice.cs

@ -1,14 +0,0 @@
using Avalonia.Input;
namespace Avalonia.Android.Platform.Input
{
public class AndroidMouseDevice : MouseDevice
{
public static AndroidMouseDevice Instance { get; } = new AndroidMouseDevice();
public AndroidMouseDevice()
{
}
}
}

6
src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs

@ -10,7 +10,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{ {
private IntPtr _window; private IntPtr _window;
public AndroidFramebuffer(Surface surface) public AndroidFramebuffer(Surface surface, double scaling)
{ {
if(surface == null) if(surface == null)
throw new ArgumentNullException(nameof(surface)); throw new ArgumentNullException(nameof(surface));
@ -31,6 +31,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
RowBytes = buffer.stride * (Format == PixelFormat.Rgb565 ? 2 : 4); RowBytes = buffer.stride * (Format == PixelFormat.Rgb565 ? 2 : 4);
Address = buffer.bits; Address = buffer.bits;
Dpi = scaling * new Vector(96, 96);
} }
public void Dispose() public void Dispose()
@ -44,7 +46,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IntPtr Address { get; set; } public IntPtr Address { get; set; }
public PixelSize Size { get; } public PixelSize Size { get; }
public int RowBytes { get; } public int RowBytes { get; }
public Vector Dpi { get; } = new Vector(96, 96); public Vector Dpi { get; }
public PixelFormat Format { get; } public PixelFormat Format { get; }
[DllImport("android")] [DllImport("android")]

2
src/Android/Avalonia.Android/Platform/SkiaPlatform/FramebufferManager.cs

@ -12,6 +12,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_topLevel = topLevel; _topLevel = topLevel;
} }
public ILockedFramebuffer Lock() => new AndroidFramebuffer(_topLevel.InternalView.Holder.Surface); public ILockedFramebuffer Lock() => new AndroidFramebuffer(_topLevel.InternalView.Holder.Surface, _topLevel.RenderScaling);
} }
} }

2
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@ -43,11 +43,13 @@ namespace Avalonia.Android
} }
} }
[Obsolete("deprecated")]
public override void Invalidate(global::Android.Graphics.Rect dirty) public override void Invalidate(global::Android.Graphics.Rect dirty)
{ {
Invalidate(); Invalidate();
} }
[Obsolete("deprecated")]
public override void Invalidate(int l, int t, int r, int b) public override void Invalidate(int l, int t, int r, int b)
{ {
Invalidate(); Invalidate();

38
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -6,7 +6,6 @@ using Android.Runtime;
using Android.Views; using Android.Views;
using Avalonia.Android.OpenGL; using Avalonia.Android.OpenGL;
using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.Specific; using Avalonia.Android.Platform.Specific;
using Avalonia.Android.Platform.Specific.Helpers; using Avalonia.Android.Platform.Specific.Helpers;
using Avalonia.Controls; using Avalonia.Controls;
@ -35,16 +34,16 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_view = new ViewImpl(context, this, placeOnTop); _view = new ViewImpl(context, this, placeOnTop);
_keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this); _keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this);
_touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(this, () => InputRoot, _touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(this, () => InputRoot,
p => GetAvaloniaPointFromEvent(p)); GetAvaloniaPointFromEvent);
_gl = GlPlatformSurface.TryCreate(this); _gl = GlPlatformSurface.TryCreate(this);
_framebuffer = new FramebufferManager(this); _framebuffer = new FramebufferManager(this);
MaxClientSize = new Size(_view.Resources.DisplayMetrics.WidthPixels, RenderScaling = (int)_view.Resources.DisplayMetrics.Density;
_view.Resources.DisplayMetrics.HeightPixels);
}
MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels,
_view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling);
}
private bool _handleEvents; private bool _handleEvents;
@ -58,25 +57,14 @@ namespace Avalonia.Android.Platform.SkiaPlatform
} }
} }
public virtual Point GetAvaloniaPointFromEvent(MotionEvent e) => new Point(e.GetX(), e.GetY()); public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) =>
new Point(e.GetX(pointerIndex), e.GetY(pointerIndex)) / RenderScaling;
public IInputRoot InputRoot { get; private set; } public IInputRoot InputRoot { get; private set; }
public virtual Size ClientSize public virtual Size ClientSize => Size.ToSize(RenderScaling);
{
get
{
if (_view == null)
return new Size(0, 0);
return new Size(_view.Width, _view.Height);
}
set
{
}
}
public IMouseDevice MouseDevice => AndroidMouseDevice.Instance; public IMouseDevice MouseDevice { get; } = new MouseDevice();
public Action Closed { get; set; } public Action Closed { get; set; }
@ -115,12 +103,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Point PointToClient(PixelPoint point) public Point PointToClient(PixelPoint point)
{ {
return point.ToPoint(1); return point.ToPoint(RenderScaling);
} }
public PixelPoint PointToScreen(Point point) public PixelPoint PointToScreen(Point point)
{ {
return PixelPoint.FromPoint(point, 1); return PixelPoint.FromPoint(point, RenderScaling);
} }
public void SetCursor(ICursorImpl cursor) public void SetCursor(ICursorImpl cursor)
@ -138,7 +126,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_view.Visibility = ViewStates.Visible; _view.Visibility = ViewStates.Visible;
} }
public double RenderScaling => 1; public double RenderScaling { get; }
void Draw() void Draw()
{ {
@ -193,7 +181,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{ {
var newSize = new Size(width, height); var newSize = new PixelSize(width, height).ToSize(_tl.RenderScaling);
if (newSize != _oldSize) if (newSize != _oldSize)
{ {

91
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs

@ -11,7 +11,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
private TView _view; private TView _view;
public bool HandleEvents { get; set; } public bool HandleEvents { get; set; }
public AndroidTouchEventsHelper(TView view, Func<IInputRoot> getInputRoot, Func<MotionEvent, Point> getPointfunc) public AndroidTouchEventsHelper(TView view, Func<IInputRoot> getInputRoot, Func<MotionEvent, int, Point> getPointfunc)
{ {
this._view = view; this._view = view;
HandleEvents = true; HandleEvents = true;
@ -19,11 +19,9 @@ namespace Avalonia.Android.Platform.Specific.Helpers
_getInputRoot = getInputRoot; _getInputRoot = getInputRoot;
} }
private DateTime _lastTouchMoveEventTime = DateTime.Now; private TouchDevice _touchDevice = new TouchDevice();
private Point? _lastTouchMovePoint; private Func<MotionEvent, int, Point> _getPointFunc;
private Func<MotionEvent, Point> _getPointFunc;
private Func<IInputRoot> _getInputRoot; private Func<IInputRoot> _getInputRoot;
private Point _point;
public bool? DispatchTouchEvent(MotionEvent e, out bool callBase) public bool? DispatchTouchEvent(MotionEvent e, out bool callBase)
{ {
@ -33,89 +31,44 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return null; return null;
} }
RawPointerEventType? mouseEventType = null;
var eventTime = DateTime.Now; var eventTime = DateTime.Now;
//Basic touch support //Basic touch support
switch (e.Action) var pointerEventType = e.Action switch
{ {
case MotionEventActions.Move: MotionEventActions.Down => RawPointerEventType.TouchBegin,
//may be bot flood the evnt system with too many event especially on not so powerfull mobile devices MotionEventActions.Up => RawPointerEventType.TouchEnd,
if ((eventTime - _lastTouchMoveEventTime).TotalMilliseconds > 10) MotionEventActions.Cancel => RawPointerEventType.TouchCancel,
{ _ => RawPointerEventType.TouchUpdate
mouseEventType = RawPointerEventType.Move; };
}
break;
case MotionEventActions.Down:
mouseEventType = RawPointerEventType.LeftButtonDown;
break; if (e.Action.HasFlag(MotionEventActions.PointerDown))
{
pointerEventType = RawPointerEventType.TouchBegin;
}
case MotionEventActions.Up: if (e.Action.HasFlag(MotionEventActions.PointerUp))
mouseEventType = RawPointerEventType.LeftButtonUp; {
break; pointerEventType = RawPointerEventType.TouchEnd;
} }
if (mouseEventType != null) for (int i = 0; i < e.PointerCount; i++)
{ {
//if point is in view otherwise it's possible avalonia not to find the proper window to dispatch the event //if point is in view otherwise it's possible avalonia not to find the proper window to dispatch the event
_point = _getPointFunc(e); var point = _getPointFunc(e, i);
double x = _view.View.GetX(); double x = _view.View.GetX();
double y = _view.View.GetY(); double y = _view.View.GetY();
double r = x + _view.View.Width; double r = x + _view.View.Width;
double b = y + _view.View.Height; double b = y + _view.View.Height;
if (x <= _point.X && r >= _point.X && y <= _point.Y && b >= _point.Y) if (x <= point.X && r >= point.X && y <= point.Y && b >= point.Y)
{ {
var inputRoot = _getInputRoot(); var inputRoot = _getInputRoot();
var mouseDevice = Avalonia.Android.Platform.Input.AndroidMouseDevice.Instance;
//in order the controls to work in a predictable way
//we need to generate mouse move before first mouse down event
//as this is the way buttons are working every time
//otherwise there is a problem sometimes
if (mouseEventType == RawPointerEventType.LeftButtonDown)
{
var me = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
RawPointerEventType.Move, _point, RawInputModifiers.None);
_view.Input(me);
}
var mouseEvent = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot, var mouseEvent = new RawTouchEventArgs(_touchDevice, (uint)eventTime.Ticks, inputRoot,
mouseEventType.Value, _point, RawInputModifiers.LeftMouseButton); i == e.ActionIndex ? pointerEventType : RawPointerEventType.TouchUpdate, point, RawInputModifiers.None, e.GetPointerId(i));
_view.Input(mouseEvent); _view.Input(mouseEvent);
if (e.Action == MotionEventActions.Move && mouseDevice.Captured == null)
{
if (_lastTouchMovePoint != null)
{
//raise mouse scroll event so the scrollers
//are moving with the cursor
double vectorX = _point.X - _lastTouchMovePoint.Value.X;
double vectorY = _point.Y - _lastTouchMovePoint.Value.Y;
//based on test correction of 0.02 is working perfect
double correction = 0.02;
var ps = AndroidPlatform.Instance.LayoutScalingFactor;
var mouseWheelEvent = new RawMouseWheelEventArgs(
mouseDevice,
(uint)eventTime.Ticks,
inputRoot,
_point,
new Vector(vectorX * correction / ps, vectorY * correction / ps), RawInputModifiers.LeftMouseButton);
_view.Input(mouseWheelEvent);
}
_lastTouchMovePoint = _point;
_lastTouchMoveEventTime = eventTime;
}
else if (e.Action == MotionEventActions.Down)
{
_lastTouchMovePoint = _point;
}
else
{
_lastTouchMovePoint = null;
}
} }
} }

11
src/Android/Avalonia.Android/app.config

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices.WindowsRuntime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

2
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@ -169,7 +169,7 @@ namespace Avalonia.DesignerSupport.Remote
if (entryPoint == null) if (entryPoint == null)
throw Die($"Assembly {args.AppPath} doesn't have an entry point"); throw Die($"Assembly {args.AppPath} doesn't have an entry point");
var builderMethod = entryPoint.DeclaringType.GetMethod(BuilderMethodName, var builderMethod = entryPoint.DeclaringType.GetMethod(BuilderMethodName,
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Array.Empty<Type>(), null);
if (builderMethod == null) if (builderMethod == null)
throw Die($"{entryPoint.DeclaringType.FullName} doesn't have a method named {BuilderMethodName}"); throw Die($"{entryPoint.DeclaringType.FullName} doesn't have a method named {BuilderMethodName}");
Design.IsDesignMode = true; Design.IsDesignMode = true;

Loading…
Cancel
Save