Browse Source

wip

android_previewer
Emmanuel Hansen 2 months ago
parent
commit
e99c19732a
  1. 6
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs
  2. 8
      src/Android/Avalonia.Android/Previewer/Preview.cs
  3. 10
      src/Android/Avalonia.Android/Previewer/PreviewFactoryActivity.cs
  4. 174
      src/Android/Avalonia.Android/Previewer/PreviewPresentation.cs
  5. 24
      src/Android/Avalonia.Android/Previewer/PreviewerConnection.cs

6
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs

@ -20,6 +20,12 @@ namespace Avalonia.Android.Platform.Specific.Helpers
private readonly TopLevelImpl _view; private readonly TopLevelImpl _view;
private bool _disposed; private bool _disposed;
public MouseDevice MouseDevice => _mouseDevice;
public TouchDevice TouchDevice => _touchDevice;
public PenDevice PenDevice => _penDevice;
public AndroidMotionEventsHelper(TopLevelImpl view) public AndroidMotionEventsHelper(TopLevelImpl view)
{ {
_touchDevice = new TouchDevice(); _touchDevice = new TouchDevice();

8
src/Android/Avalonia.Android/Previewer/Preview.cs

@ -87,10 +87,18 @@ namespace Avalonia.Android.Previewer
} }
else if (root is TopLevel) else if (root is TopLevel)
{ {
// We can't host toplevels
topLevel!.Content = null; topLevel!.Content = null;
} }
else else
{ {
if(root is Visual visual)
{
if (visual.IsSet(AvDesign.DataContextProperty))
{
visual.DataContext = visual.GetValue(AvDesign.DataContextProperty);
}
}
topLevel!.Content = root; topLevel!.Content = root;
} }
return true; return true;

10
src/Android/Avalonia.Android/Previewer/PreviewFactoryActivity.cs

@ -29,12 +29,12 @@ namespace Avalonia.Android.Previewer
display?.StartDisplay(); display?.StartDisplay();
if (display != null) if (display != null)
{ {
var assembly = Assembly.GetAssembly(typeof(TApp)); var assembly = Assembly.GetAssembly(typeof(TApp));
var presentation = new PreviewPresentation(this, display.Display, port, assembly); var presentation = new PreviewPresentation(this, display.Display, port, assembly);
presentation.Show(); presentation.Show();
}
} }
}
global::Android.Util.Log.Info("AVALONIA_PREVIEW", $"Previewer started at port-{port}"); global::Android.Util.Log.Info("AVALONIA_PREVIEW", $"Previewer started at port-{port}");
} }

174
src/Android/Avalonia.Android/Previewer/PreviewPresentation.cs

@ -1,17 +1,16 @@
using System; using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
using Android.Content.PM;
using Android.OS; using Android.OS;
using Android.Runtime;
using Android.Views; using Android.Views;
using Avalonia.Media; using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Remote.Protocol.Input;
using Avalonia.Threading;
using Key = Avalonia.Input.Key;
using PhysicalKey = Avalonia.Input.PhysicalKey;
namespace Avalonia.Android.Previewer namespace Avalonia.Android.Previewer
{ {
@ -26,6 +25,9 @@ namespace Avalonia.Android.Previewer
private AvaloniaView? _view; private AvaloniaView? _view;
private float _renderScaling = 1; private float _renderScaling = 1;
internal MouseDevice? TouchDevice => _view?.TopLevelImpl.PointerHelper.MouseDevice;
internal static KeyboardDevice? KeyboardDevice => AvaloniaLocator.Current.GetService<IKeyboardDevice>() as KeyboardDevice;
public AvaloniaView? View { get => _view; set => _view = value; } public AvaloniaView? View { get => _view; set => _view = value; }
public float RenderScaling public float RenderScaling
@ -34,7 +36,7 @@ namespace Avalonia.Android.Previewer
internal set internal set
{ {
_renderScaling = value; _renderScaling = value;
if(PreviewDisplay.Instance?.Surface is { } surface) if (PreviewDisplay.Instance?.Surface is { } surface)
{ {
surface.Scaling = _renderScaling; surface.Scaling = _renderScaling;
} }
@ -50,7 +52,7 @@ namespace Avalonia.Android.Previewer
_assembly = assembly; _assembly = assembly;
} }
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
Justification = "<Pending>")] Justification = "<Pending>")]
protected override void OnCreate(Bundle? savedInstanceState) protected override void OnCreate(Bundle? savedInstanceState)
{ {
@ -71,5 +73,157 @@ namespace Avalonia.Android.Previewer
if (_preview != null) if (_preview != null)
await _preview.UpdateXamlAsync(xaml); await _preview.UpdateXamlAsync(xaml);
} }
public void SendInput(InputEventMessageBase input)
{
switch (input)
{
case PointerMovedEventMessage pointer:
Dispatcher.UIThread.Post(() =>
{
View?.TopLevelImpl?.Input?.Invoke(new RawPointerEventArgs(
TouchDevice!,
0,
View?.TopLevelImpl?.InputRoot!,
RawPointerEventType.Move,
new Point(pointer.X, pointer.Y),
GetAvaloniaRawInputModifiers(pointer.Modifiers)));
}, DispatcherPriority.Input);
break;
case PointerPressedEventMessage pressed:
Dispatcher.UIThread.Post(() =>
{
View?.TopLevelImpl?.Input?.Invoke(new RawPointerEventArgs(
TouchDevice!,
0,
View?.TopLevelImpl.InputRoot!,
GetAvaloniaEventType(pressed.Button, true),
new Point(pressed.X, pressed.Y),
GetAvaloniaRawInputModifiers(pressed.Modifiers)));
}, DispatcherPriority.Input);
break;
case PointerReleasedEventMessage released:
Dispatcher.UIThread.Post(() =>
{
View?.TopLevelImpl?.Input?.Invoke(new RawPointerEventArgs(
TouchDevice!,
0,
View?.TopLevelImpl.InputRoot!,
GetAvaloniaEventType(released.Button, false),
new Point(released.X, released.Y),
GetAvaloniaRawInputModifiers(released.Modifiers)));
}, DispatcherPriority.Input);
break;
case ScrollEventMessage scroll:
Dispatcher.UIThread.Post(() =>
{
View?.TopLevelImpl?.Input?.Invoke(new RawMouseWheelEventArgs(
TouchDevice!,
0,
View?.TopLevelImpl.InputRoot!,
new Point(scroll.X, scroll.Y),
new Vector(scroll.DeltaX, scroll.DeltaY),
GetAvaloniaRawInputModifiers(scroll.Modifiers)));
}, DispatcherPriority.Input);
break;
case KeyEventMessage key:
Dispatcher.UIThread.Post(() =>
{
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
View?.TopLevelImpl?.Input?.Invoke(new RawKeyEventArgs(
KeyboardDevice!,
0,
View?.TopLevelImpl.InputRoot!,
key.IsDown ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
(Key)key.Key,
GetAvaloniaRawInputModifiers(key.Modifiers),
(PhysicalKey)key.PhysicalKey,
key.KeySymbol));
}, DispatcherPriority.Input);
break;
case TextInputEventMessage text:
Dispatcher.UIThread.Post(() =>
{
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
View?.TopLevelImpl?.Input?.Invoke(new RawTextInputEventArgs(
KeyboardDevice!,
0,
View?.TopLevelImpl.InputRoot!,
text.Text));
}, DispatcherPriority.Input);
break;
}
}
private static RawPointerEventType GetAvaloniaEventType(Remote.Protocol.Input.MouseButton button, bool pressed)
{
switch (button)
{
case Remote.Protocol.Input.MouseButton.Left:
return pressed ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp;
case Remote.Protocol.Input.MouseButton.Middle:
return pressed ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp;
case Remote.Protocol.Input.MouseButton.Right:
return pressed ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp;
default:
return RawPointerEventType.Move;
}
}
private static RawInputModifiers GetAvaloniaRawInputModifiers(InputModifiers[]? modifiers)
{
var result = RawInputModifiers.None;
if (modifiers == null)
{
return result;
}
foreach (var modifier in modifiers)
{
switch (modifier)
{
case InputModifiers.Control:
result |= RawInputModifiers.Control;
break;
case InputModifiers.Alt:
result |= RawInputModifiers.Alt;
break;
case InputModifiers.Shift:
result |= RawInputModifiers.Shift;
break;
case InputModifiers.Windows:
result |= RawInputModifiers.Meta;
break;
case InputModifiers.LeftMouseButton:
result |= RawInputModifiers.LeftMouseButton;
break;
case InputModifiers.MiddleMouseButton:
result |= RawInputModifiers.MiddleMouseButton;
break;
case InputModifiers.RightMouseButton:
result |= RawInputModifiers.RightMouseButton;
break;
}
}
return result;
}
} }
} }

24
src/Android/Avalonia.Android/Previewer/PreviewerConnection.cs

@ -1,19 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using Avalonia.Layout;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Media;
using Avalonia.Remote.Protocol; using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Designer; using Avalonia.Remote.Protocol.Designer;
using Avalonia.Remote.Protocol.Input; using Avalonia.Remote.Protocol.Input;
using Avalonia.Remote.Protocol.Viewport; using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Threading; using Avalonia.Threading;
using Java.Text;
namespace Avalonia.Android.Previewer namespace Avalonia.Android.Previewer
{ {
@ -90,6 +83,21 @@ namespace Avalonia.Android.Previewer
}); });
} }
break; break;
case MeasureViewportMessage measure:
var root = previewPresentation.View?.TopLevelImpl.InputRoot as Layoutable;
root?.Measure(new Size(measure.Width, measure.Height));
var desiredSize = root?.DesiredSize ?? default;
_connection?.Send(new MeasureViewportMessage
{
Width = desiredSize.Width,
Height = desiredSize.Height
});
break;
case InputEventMessageBase inputEventMessage:
previewPresentation?.SendInput(inputEventMessage);
break;
} }
}, arg2); }, arg2);
} }

Loading…
Cancel
Save