Browse Source

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

pull/5683/head
Jumar Macato 5 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
{
class AndroidPlatform : IPlatformSettings, IWindowingPlatform
class AndroidPlatform : IPlatformSettings
{
public static readonly AndroidPlatform Instance = new AndroidPlatform();
public static AndroidPlatformOptions Options { get; private set; }
public Size DoubleClickSize => new Size(4, 4);
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)
{
@ -56,7 +47,6 @@ namespace Avalonia.Android
.Bind<IPlatformSettings>().ToConstant(Instance)
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(Instance)
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
@ -70,16 +60,6 @@ namespace Avalonia.Android
EglPlatformOpenGlInterface.TryInitialize();
}
}
public IWindowImpl CreateWindow()
{
throw new NotSupportedException();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotSupportedException();
}
}
public sealed class AndroidPlatformOptions

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

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

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

@ -1,4 +1,3 @@
using Android.App;
using Android.OS;
using Android.Views;
@ -7,7 +6,6 @@ namespace Avalonia.Android
{
public abstract class AvaloniaActivity : Activity
{
internal AvaloniaView View;
object _content;
@ -35,9 +33,7 @@ namespace Avalonia.Android
}
}
public override bool DispatchKeyEvent(KeyEvent e)
{
return View.DispatchKeyEvent(e);
}
public override bool DispatchKeyEvent(KeyEvent e) =>
View.DispatchKeyEvent(e) ? true : base.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;
public AndroidFramebuffer(Surface surface)
public AndroidFramebuffer(Surface surface, double scaling)
{
if(surface == null)
throw new ArgumentNullException(nameof(surface));
@ -31,6 +31,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
RowBytes = buffer.stride * (Format == PixelFormat.Rgb565 ? 2 : 4);
Address = buffer.bits;
Dpi = scaling * new Vector(96, 96);
}
public void Dispose()
@ -44,7 +46,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IntPtr Address { get; set; }
public PixelSize Size { get; }
public int RowBytes { get; }
public Vector Dpi { get; } = new Vector(96, 96);
public Vector Dpi { get; }
public PixelFormat Format { get; }
[DllImport("android")]

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

@ -12,6 +12,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_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)
{
Invalidate();
}
[Obsolete("deprecated")]
public override void Invalidate(int l, int t, int r, int b)
{
Invalidate();

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

@ -6,7 +6,6 @@ using Android.Runtime;
using Android.Views;
using Avalonia.Android.OpenGL;
using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.Specific;
using Avalonia.Android.Platform.Specific.Helpers;
using Avalonia.Controls;
@ -35,16 +34,16 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_view = new ViewImpl(context, this, placeOnTop);
_keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this);
_touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(this, () => InputRoot,
p => GetAvaloniaPointFromEvent(p));
GetAvaloniaPointFromEvent);
_gl = GlPlatformSurface.TryCreate(this);
_framebuffer = new FramebufferManager(this);
MaxClientSize = new Size(_view.Resources.DisplayMetrics.WidthPixels,
_view.Resources.DisplayMetrics.HeightPixels);
}
RenderScaling = (int)_view.Resources.DisplayMetrics.Density;
MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels,
_view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling);
}
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 virtual Size ClientSize
{
get
{
if (_view == null)
return new Size(0, 0);
return new Size(_view.Width, _view.Height);
}
set
{
}
}
public virtual Size ClientSize => Size.ToSize(RenderScaling);
public IMouseDevice MouseDevice => AndroidMouseDevice.Instance;
public IMouseDevice MouseDevice { get; } = new MouseDevice();
public Action Closed { get; set; }
@ -115,12 +103,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Point PointToClient(PixelPoint point)
{
return point.ToPoint(1);
return point.ToPoint(RenderScaling);
}
public PixelPoint PointToScreen(Point point)
{
return PixelPoint.FromPoint(point, 1);
return PixelPoint.FromPoint(point, RenderScaling);
}
public void SetCursor(ICursorImpl cursor)
@ -138,7 +126,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_view.Visibility = ViewStates.Visible;
}
public double RenderScaling => 1;
public double RenderScaling { get; }
void Draw()
{
@ -193,7 +181,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
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)
{

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

@ -11,7 +11,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
private TView _view;
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;
HandleEvents = true;
@ -19,11 +19,9 @@ namespace Avalonia.Android.Platform.Specific.Helpers
_getInputRoot = getInputRoot;
}
private DateTime _lastTouchMoveEventTime = DateTime.Now;
private Point? _lastTouchMovePoint;
private Func<MotionEvent, Point> _getPointFunc;
private TouchDevice _touchDevice = new TouchDevice();
private Func<MotionEvent, int, Point> _getPointFunc;
private Func<IInputRoot> _getInputRoot;
private Point _point;
public bool? DispatchTouchEvent(MotionEvent e, out bool callBase)
{
@ -33,89 +31,44 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return null;
}
RawPointerEventType? mouseEventType = null;
var eventTime = DateTime.Now;
//Basic touch support
switch (e.Action)
var pointerEventType = e.Action switch
{
case MotionEventActions.Move:
//may be bot flood the evnt system with too many event especially on not so powerfull mobile devices
if ((eventTime - _lastTouchMoveEventTime).TotalMilliseconds > 10)
{
mouseEventType = RawPointerEventType.Move;
}
break;
case MotionEventActions.Down:
mouseEventType = RawPointerEventType.LeftButtonDown;
MotionEventActions.Down => RawPointerEventType.TouchBegin,
MotionEventActions.Up => RawPointerEventType.TouchEnd,
MotionEventActions.Cancel => RawPointerEventType.TouchCancel,
_ => RawPointerEventType.TouchUpdate
};
break;
if (e.Action.HasFlag(MotionEventActions.PointerDown))
{
pointerEventType = RawPointerEventType.TouchBegin;
}
case MotionEventActions.Up:
mouseEventType = RawPointerEventType.LeftButtonUp;
break;
if (e.Action.HasFlag(MotionEventActions.PointerUp))
{
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
_point = _getPointFunc(e);
var point = _getPointFunc(e, i);
double x = _view.View.GetX();
double y = _view.View.GetY();
double r = x + _view.View.Width;
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 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,
mouseEventType.Value, _point, RawInputModifiers.LeftMouseButton);
var mouseEvent = new RawTouchEventArgs(_touchDevice, (uint)eventTime.Ticks, inputRoot,
i == e.ActionIndex ? pointerEventType : RawPointerEventType.TouchUpdate, point, RawInputModifiers.None, e.GetPointerId(i));
_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)
throw Die($"Assembly {args.AppPath} doesn't have an entry point");
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)
throw Die($"{entryPoint.DeclaringType.FullName} doesn't have a method named {BuilderMethodName}");
Design.IsDesignMode = true;

Loading…
Cancel
Save