Browse Source

restrict souce of input event sto parent view on android (#19289)

pull/19387/head
Emmanuel Hansen 1 year ago
committed by GitHub
parent
commit
74e8ce7efa
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      src/Android/Avalonia.Android/AvaloniaActivity.cs
  2. 67
      src/Android/Avalonia.Android/AvaloniaView.Input.cs
  3. 21
      src/Android/Avalonia.Android/AvaloniaView.cs
  4. 3
      src/Android/Avalonia.Android/Platform/Input/AndroidInputMethod.cs
  5. 61
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

5
src/Android/Avalonia.Android/AvaloniaActivity.cs

@ -8,10 +8,10 @@ using Android.OS;
using Android.Runtime;
using Android.Views;
using AndroidX.AppCompat.App;
using Avalonia.Platform;
using Avalonia.Android.Platform;
using Avalonia.Android.Platform.Storage;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
namespace Avalonia.Android;
@ -48,6 +48,9 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity
SetContentView(_view);
// By default, the view isn't focused if the activity is created anew, so we force focus.
_view.RequestFocus();
_listener = new GlobalLayoutListener(_view);
_view.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener);

67
src/Android/Avalonia.Android/AvaloniaView.Input.cs

@ -0,0 +1,67 @@
using System;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
namespace Avalonia.Android
{
public partial class AvaloniaView : IInitEditorInfo
{
private Func<TopLevelImpl, EditorInfo, IInputConnection>? _initEditorInfo;
public override IInputConnection OnCreateInputConnection(EditorInfo? outAttrs)
{
return _initEditorInfo?.Invoke(_view, outAttrs!)!;
}
void IInitEditorInfo.InitEditorInfo(Func<TopLevelImpl, EditorInfo, IInputConnection> init)
{
_initEditorInfo = init;
}
protected override void OnFocusChanged(bool gainFocus, FocusSearchDirection direction, global::Android.Graphics.Rect? previouslyFocusedRect)
{
base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
_accessHelper.OnFocusChanged(gainFocus, (int)direction, previouslyFocusedRect);
}
protected override bool DispatchHoverEvent(MotionEvent? e)
{
return _accessHelper.DispatchHoverEvent(e!) || base.DispatchHoverEvent(e);
}
protected override bool DispatchGenericPointerEvent(MotionEvent? e)
{
var result = _view.PointerHelper.DispatchMotionEvent(e, out var callBase);
var baseResult = callBase && base.DispatchGenericPointerEvent(e);
return result ?? baseResult;
}
public override bool DispatchTouchEvent(MotionEvent? e)
{
var result = _view.PointerHelper.DispatchMotionEvent(e, out var callBase);
var baseResult = callBase && base.DispatchTouchEvent(e);
if(result == true)
{
// Request focus for this view
RequestFocus();
}
return result ?? baseResult;
}
public override bool DispatchKeyEvent(KeyEvent? e)
{
var res = _view.KeyboardHelper.DispatchKeyEvent(e, out var callBase);
if (res == false)
callBase = !_accessHelper.DispatchKeyEvent(e!) && callBase;
var baseResult = callBase && base.DispatchKeyEvent(e);
return res ?? baseResult;
}
}
}

21
src/Android/Avalonia.Android/AvaloniaView.cs

@ -17,7 +17,7 @@ using Avalonia.Rendering;
namespace Avalonia.Android
{
public class AvaloniaView : FrameLayout
public partial class AvaloniaView : FrameLayout
{
private EmbeddableControlRoot _root;
private readonly ViewImpl _view;
@ -71,24 +71,6 @@ namespace Avalonia.Android
_root = null!;
}
protected override void OnFocusChanged(bool gainFocus, FocusSearchDirection direction, global::Android.Graphics.Rect? previouslyFocusedRect)
{
base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
_accessHelper.OnFocusChanged(gainFocus, (int)direction, previouslyFocusedRect);
}
protected override bool DispatchHoverEvent(MotionEvent? e)
{
return _accessHelper.DispatchHoverEvent(e!) || base.DispatchHoverEvent(e);
}
public override bool DispatchKeyEvent(KeyEvent? e)
{
if (!_view.View.DispatchKeyEvent(e))
return _accessHelper.DispatchKeyEvent(e!) || base.DispatchKeyEvent(e);
return true;
}
[SupportedOSPlatform("android24.0")]
public override void OnVisibilityAggregated(bool isVisible)
{
@ -149,7 +131,6 @@ namespace Avalonia.Android
{
public ViewImpl(AvaloniaView avaloniaView) : base(avaloniaView)
{
View.Focusable = true;
View.FocusChange += ViewImpl_FocusChange;
}

3
src/Android/Avalonia.Android/Platform/Input/AndroidInputMethod.cs

@ -44,9 +44,6 @@ namespace Avalonia.Android.Platform.Input
public AndroidInputMethod(TView host)
{
if (host.OnCheckIsTextEditor() == false)
throw new InvalidOperationException("Host should return true from OnCheckIsTextEditor()");
_host = host;
_imm = host.Context?.GetSystemService(Context.InputMethodService).JavaCast<InputMethodManager>()
?? throw new InvalidOperationException("Context.InputMethodService is expected to be not null.");

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

@ -5,9 +5,7 @@ using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using AndroidX.AppCompat.App;
using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.Specific;
@ -15,13 +13,11 @@ using Avalonia.Android.Platform.Specific.Helpers;
using Avalonia.Android.Platform.Storage;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Rendering.Composition;
@ -34,7 +30,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
private readonly AndroidKeyboardEventsHelper<TopLevelImpl> _keyboardHelper;
private readonly AndroidMotionEventsHelper _pointerHelper;
private readonly AndroidInputMethod<ViewImpl> _textInputMethod;
private readonly AndroidInputMethod<AvaloniaView> _textInputMethod;
private readonly INativeControlHostImpl _nativeControlHost;
private readonly IStorageProvider? _storageProvider;
private readonly AndroidSystemNavigationManagerImpl _systemNavigationManager;
@ -42,7 +38,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
private readonly ClipboardImpl _clipboard;
private readonly AndroidLauncher? _launcher;
private readonly AndroidScreens? _screens;
private ViewImpl _view;
private SurfaceViewImpl _view;
private WindowTransparencyLevel _transparencyLevel;
public TopLevelImpl(AvaloniaView avaloniaView, bool placeOnTop = false)
@ -52,8 +48,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
throw new ArgumentException("AvaloniaView.Context must not be null");
}
_view = new ViewImpl(avaloniaView.Context, this, placeOnTop);
_textInputMethod = new AndroidInputMethod<ViewImpl>(_view);
_view = new SurfaceViewImpl(avaloniaView.Context, this, placeOnTop);
_textInputMethod = new AndroidInputMethod<AvaloniaView>(avaloniaView);
_keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this);
_pointerHelper = new AndroidMotionEventsHelper(this);
_clipboard = new ClipboardImpl(avaloniaView.Context.GetSystemService(Context.ClipboardService).JavaCast<ClipboardManager>());
@ -141,13 +137,13 @@ namespace Avalonia.Android.Platform.SkiaPlatform
Resized?.Invoke(size, WindowResizeReason.Layout);
}
sealed class ViewImpl : InvalidationAwareSurfaceView, IInitEditorInfo
sealed class SurfaceViewImpl : InvalidationAwareSurfaceView
{
private readonly TopLevelImpl _tl;
private Size _oldSize;
private double _oldScaling;
public ViewImpl(Context context, TopLevelImpl tl, bool placeOnTop) : base(context)
public SurfaceViewImpl(Context context, TopLevelImpl tl, bool placeOnTop) : base(context)
{
_tl = tl;
if (placeOnTop)
@ -176,30 +172,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
base.DispatchDraw(canvas);
}
protected override bool DispatchGenericPointerEvent(MotionEvent? e)
{
var result = _tl._pointerHelper.DispatchMotionEvent(e, out var callBase);
var baseResult = callBase && base.DispatchGenericPointerEvent(e);
return result ?? baseResult;
}
public override bool DispatchTouchEvent(MotionEvent? e)
{
var result = _tl._pointerHelper.DispatchMotionEvent(e, out var callBase);
var baseResult = callBase && base.DispatchTouchEvent(e);
return result ?? baseResult;
}
public override bool DispatchKeyEvent(KeyEvent? e)
{
var res = _tl._keyboardHelper.DispatchKeyEvent(e, out var callBase);
var baseResult = callBase && base.DispatchKeyEvent(e);
return res ?? baseResult;
}
public override void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{
base.SurfaceChanged(holder, format, width, height);
@ -232,23 +204,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_tl.Compositor.RequestCompositionUpdate(drawingFinished.Run);
base.SurfaceRedrawNeededAsync(holder, drawingFinished);
}
public override bool OnCheckIsTextEditor()
{
return true;
}
private Func<TopLevelImpl, EditorInfo, IInputConnection>? _initEditorInfo;
public void InitEditorInfo(Func<TopLevelImpl, EditorInfo, IInputConnection> init)
{
_initEditorInfo = init;
}
public override IInputConnection OnCreateInputConnection(EditorInfo? outAttrs)
{
return _initEditorInfo?.Invoke(_tl, outAttrs!)!;
}
}
public IPopupImpl? CreatePopup() => null;
@ -291,6 +246,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
PixelSize EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Size => _view.Size;
double EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Scaling => _view.Scaling;
internal AndroidKeyboardEventsHelper<TopLevelImpl> KeyboardHelper => _keyboardHelper;
internal AndroidMotionEventsHelper PointerHelper => _pointerHelper;
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
{
if (_view.Context is not AvaloniaMainActivity activity)

Loading…
Cancel
Save