Skip to content

Commit

Permalink
Enable nullable on Avalonia.Android project (#15331)
Browse files Browse the repository at this point in the history
* Enable nullable on Avalonia.Android project

* More specific exception
  • Loading branch information
maxkatz6 authored Apr 12, 2024
1 parent 6f7a003 commit 6258df5
Show file tree
Hide file tree
Showing 33 changed files with 195 additions and 218 deletions.
33 changes: 19 additions & 14 deletions src/Android/Avalonia.Android/AndroidInputMethod.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Android.Content;
using Android.Runtime;
using Android.Text;
Expand All @@ -13,8 +14,9 @@ internal interface IAndroidInputMethod
{
public View View { get; }

public TextInputMethodClient Client { get; }
public TextInputMethodClient? Client { get; }

[MemberNotNullWhen(true, nameof(Client))]
public bool IsActive { get; }

public InputMethodManager IMM { get; }
Expand All @@ -38,26 +40,29 @@ internal class AndroidInputMethod<TView> : ITextInputMethodImpl, IAndroidInputMe
{
private readonly TView _host;
private readonly InputMethodManager _imm;
private TextInputMethodClient _client;
private AvaloniaInputConnection _inputConnection;
private TextInputMethodClient? _client;
private AvaloniaInputConnection? _inputConnection;

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>();
_imm = host.Context?.GetSystemService(Context.InputMethodService).JavaCast<InputMethodManager>()
?? throw new InvalidOperationException("Context.InputMethodService is expected to be not null.");

_host.Focusable = true;
_host.FocusableInTouchMode = true;
}

public View View => _host;

[MemberNotNullWhen(true, nameof(Client))]
[MemberNotNullWhen(true, nameof(_client))]
public bool IsActive => Client != null;

public TextInputMethodClient Client => _client;
public TextInputMethodClient? Client => _client;

public InputMethodManager IMM => _imm;

Expand All @@ -66,7 +71,7 @@ public void Reset()

}

public void SetClient(TextInputMethodClient client)
public void SetClient(TextInputMethodClient? client)
{
_client = client;

Expand Down Expand Up @@ -103,9 +108,9 @@ public void SetClient(TextInputMethodClient client)
}
}

private void _client_SelectionChanged(object sender, EventArgs e)
private void _client_SelectionChanged(object? sender, EventArgs e)
{
if (_inputConnection.IsInBatchEdit)
if (_inputConnection is null || _inputConnection.IsInBatchEdit)
return;
OnSelectionChanged();
}
Expand All @@ -121,19 +126,19 @@ private void OnSelectionChanged()

_imm.UpdateSelection(_host, selection.Start, selection.End, selection.Start, selection.End);

_inputConnection.SetSelection(selection.Start, selection.End);
_inputConnection?.SetSelection(selection.Start, selection.End);
}

private void _client_SurroundingTextChanged(object sender, EventArgs e)
private void _client_SurroundingTextChanged(object? sender, EventArgs e)
{
if (_inputConnection.IsInBatchEdit)
if (_inputConnection is null || _inputConnection.IsInBatchEdit)
return;
OnSurroundingTextChanged();
}

public void OnBatchEditedEnded()
{
if (_inputConnection.IsInBatchEdit)
if (_inputConnection is null || _inputConnection.IsInBatchEdit)
return;

OnSurroundingTextChanged();
Expand All @@ -142,7 +147,7 @@ public void OnBatchEditedEnded()

private void OnSurroundingTextChanged()
{
if(_client is null)
if(_client is null || _inputConnection is null)
{
return;
}
Expand Down Expand Up @@ -199,7 +204,7 @@ public void SetOptions(TextInputOptions options)
_host.InitEditorInfo((topLevel, outAttrs) =>
{
if (_client == null)
return null;
return null!;

_inputConnection = new AvaloniaInputConnection(topLevel, this);

Expand Down
8 changes: 3 additions & 5 deletions src/Android/Avalonia.Android/AndroidPlatform.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Android;
using Avalonia.Android.Platform;
using Avalonia.Android.Platform.Input;
Expand All @@ -12,7 +11,6 @@
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.OpenGL;

namespace Avalonia
{
Expand Down Expand Up @@ -66,9 +64,9 @@ namespace Avalonia.Android
class AndroidPlatform
{
public static readonly AndroidPlatform Instance = new AndroidPlatform();
public static AndroidPlatformOptions Options { get; private set; }
public static AndroidPlatformOptions? Options { get; private set; }

internal static Compositor Compositor { get; private set; }
internal static Compositor? Compositor { get; private set; }

public static void Initialize()
{
Expand All @@ -95,7 +93,7 @@ public static void Initialize()
AvaloniaLocator.CurrentMutable.Bind<Compositor>().ToConstant(Compositor);
}

private static IPlatformGraphics InitializeGraphics(AndroidPlatformOptions opts)
private static IPlatformGraphics? InitializeGraphics(AndroidPlatformOptions opts)
{
if (opts.RenderingMode is null || !opts.RenderingMode.Any())
{
Expand Down
4 changes: 1 addition & 3 deletions src/Android/Avalonia.Android/AndroidRuntimePlatform.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#nullable enable

using System;
using System;
using Android.Content.PM;
using Android.Content;
using Avalonia.Platform;
Expand Down
17 changes: 9 additions & 8 deletions src/Android/Avalonia.Android/AndroidThreadingInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ namespace Avalonia.Android
internal sealed class AndroidThreadingInterface : IPlatformThreadingInterface
{
private Handler _handler;
private static Thread s_uiThread;
private static Thread? s_uiThread;

public AndroidThreadingInterface()
{
_handler = new Handler(App.Context.MainLooper);
_handler = new Handler(App.Context.MainLooper
?? throw new InvalidOperationException("Application.Context.MainLooper was not expected to be null."));
}

public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
Expand All @@ -27,7 +28,7 @@ public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Ac
interval = TimeSpan.FromMilliseconds(10);

var stopped = false;
Timer timer = null;
Timer? timer = null;
timer = new Timer(_ =>
{
if (stopped)
Expand All @@ -42,7 +43,7 @@ public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Ac
finally
{
if (!stopped)
timer.Change(interval, Timeout.InfiniteTimeSpan);
timer!.Change(interval, Timeout.InfiniteTimeSpan);
}
});
},
Expand Down Expand Up @@ -70,9 +71,9 @@ public bool CurrentThreadIsLoopThread
return s_uiThread == Thread.CurrentThread;

var isOnMainThread = OperatingSystem.IsAndroidVersionAtLeast(23)
? Looper.MainLooper.IsCurrentThread
: Looper.MainLooper.Thread.Equals(Java.Lang.Thread.CurrentThread());
if (isOnMainThread)
? Looper.MainLooper?.IsCurrentThread
: Looper.MainLooper?.Thread.Equals(Java.Lang.Thread.CurrentThread());
if (isOnMainThread == true)
{
s_uiThread = Thread.CurrentThread;
return true;
Expand All @@ -81,6 +82,6 @@ public bool CurrentThreadIsLoopThread
return false;
}
}
public event Action<DispatcherPriority?> Signaled;
public event Action<DispatcherPriority?>? Signaled;
}
}
4 changes: 1 addition & 3 deletions src/Android/Avalonia.Android/AndroidViewControlHandle.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#nullable enable

using System;
using System;

using Android.Views;

Expand Down
3 changes: 2 additions & 1 deletion src/Android/Avalonia.Android/Avalonia.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<TargetFramework>$(AvsCurrentAndroidTargetFramework)</TargetFramework>
<SupportedOSPlatformVersion>$(AvsMinSupportedAndroidVersion)</SupportedOSPlatformVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>portable</DebugType>
<AndroidResgenNamespace>Avalonia.Android.Internal</AndroidResgenNamespace>
</PropertyGroup>
<ItemGroup>
Expand All @@ -16,6 +15,8 @@
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>

<Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
</Project>
1 change: 0 additions & 1 deletion src/Android/Avalonia.Android/AvaloniaActivity.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Versioning;
Expand Down
10 changes: 1 addition & 9 deletions src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
#nullable enable

using Android.OS;
using Android.Views;
using Avalonia.Android.Platform;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;

namespace Avalonia.Android;
namespace Avalonia.Android;

public class AvaloniaMainActivity<TApp> : AvaloniaMainActivity
where TApp : Application, new()
Expand Down
3 changes: 0 additions & 3 deletions src/Android/Avalonia.Android/AvaloniaMainActivity.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
#nullable enable

using System;
using System.Diagnostics.CodeAnalysis;
using Android.OS;
using Avalonia.Android.Platform;
using Avalonia.Controls.ApplicationLifetimes;
Expand Down
28 changes: 13 additions & 15 deletions src/Android/Avalonia.Android/AvaloniaView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class AvaloniaView : FrameLayout
private EmbeddableControlRoot _root;
private readonly ViewImpl _view;

private IDisposable _timerSubscription;
private IDisposable? _timerSubscription;

public AvaloniaView(Context context) : base(context)
{
Expand All @@ -35,9 +35,9 @@ public AvaloniaView(Context context) : base(context)
}

internal TopLevelImpl TopLevelImpl => _view;
internal TopLevel TopLevel => _root;
internal TopLevel? TopLevel => _root;

public object Content
public object? Content
{
get { return _root.Content; }
set { _root.Content = value; }
Expand All @@ -47,10 +47,10 @@ protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_root?.Dispose();
_root = null;
_root = null!;
}

public override bool DispatchKeyEvent(KeyEvent e)
public override bool DispatchKeyEvent(KeyEvent? e)
{
return _view.View.DispatchKeyEvent(e);
}
Expand Down Expand Up @@ -91,16 +91,20 @@ private void OnVisibilityChanged(bool isVisible)
}
}

protected override void OnConfigurationChanged(Configuration newConfig)
protected override void OnConfigurationChanged(Configuration? newConfig)
{
base.OnConfigurationChanged(newConfig);
OnConfigurationChanged();
}

private void OnConfigurationChanged()
{
var settings = AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>() as AndroidPlatformSettings;
settings?.OnViewConfigurationChanged(Context);
if (Context is { } context)
{
var settings =
AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>() as AndroidPlatformSettings;
settings?.OnViewConfigurationChanged(context);
}
}

class ViewImpl : TopLevelImpl
Expand All @@ -111,17 +115,11 @@ public ViewImpl(AvaloniaView avaloniaView) : base(avaloniaView)
View.FocusChange += ViewImpl_FocusChange;
}

private void ViewImpl_FocusChange(object sender, FocusChangeEventArgs e)
private void ViewImpl_FocusChange(object? sender, FocusChangeEventArgs e)
{
if(!e.HasFocus)
LostFocus?.Invoke();
}

protected override void OnResized(Size size)
{
MaxClientSize = size;
base.OnResized(size);
}
}
}
}
13 changes: 6 additions & 7 deletions src/Android/Avalonia.Android/ChoreographerTimer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,22 @@ namespace Avalonia.Android
{
internal sealed class ChoreographerTimer : Java.Lang.Object, IRenderTimer, Choreographer.IFrameCallback
{
private readonly object _lock = new object();
private readonly object _lock = new();

private readonly Thread _thread;
private readonly TaskCompletionSource<Choreographer> _choreographer = new TaskCompletionSource<Choreographer>();
private readonly TaskCompletionSource<Choreographer> _choreographer = new();

private readonly ISet<AvaloniaView> _views = new HashSet<AvaloniaView>();

private Action<TimeSpan> _tick;
private Action<TimeSpan>? _tick;
private int _count;

public ChoreographerTimer()
{
_thread = new Thread(Loop);
_thread.Start();
}



public bool RunsInBackground => true;

public event Action<TimeSpan> Tick
Expand Down Expand Up @@ -84,7 +83,7 @@ internal IDisposable SubscribeView(AvaloniaView view)
private void Loop()
{
Looper.Prepare();
_choreographer.SetResult(Choreographer.Instance);
_choreographer.SetResult(Choreographer.Instance!);
Looper.Loop();
}

Expand All @@ -96,7 +95,7 @@ public void DoFrame(long frameTimeNanos)
{
if (_count > 0 && _views.Count > 0)
{
Choreographer.Instance.PostFrameCallback(this);
Choreographer.Instance!.PostFrameCallback(this);
}
}
}
Expand Down
Loading

0 comments on commit 6258df5

Please sign in to comment.