From 98e60e89c7d49c7b2d2028953e95d3ac56503930 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Tue, 13 Aug 2024 04:03:22 +0000 Subject: [PATCH] android - defer rendering till surface is created (#16616) --- .../Avalonia.Android/AvaloniaActivity.cs | 2 +- .../Avalonia.Android/AvaloniaMainActivity.cs | 2 +- src/Android/Avalonia.Android/AvaloniaView.cs | 20 +++++++++++++++++-- .../InvalidationAwareSurfaceView.cs | 11 +++++++++- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs index 7117595787..fa3484f058 100644 --- a/src/Android/Avalonia.Android/AvaloniaActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -155,7 +155,7 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity base.OnDestroy(); } - + protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent? data) { base.OnActivityResult(requestCode, resultCode, data); diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs index 639082ed02..63097b22a1 100644 --- a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs @@ -21,8 +21,8 @@ public class AvaloniaMainActivity : AvaloniaActivity { initialContent ??= Lifetime.MainView; - Lifetime.Activity = this; _view = new AvaloniaView(this) { Content = initialContent }; + Lifetime.Activity = this; } else { diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs index aa5124dcea..b5a4287fb0 100644 --- a/src/Android/Avalonia.Android/AvaloniaView.cs +++ b/src/Android/Avalonia.Android/AvaloniaView.cs @@ -21,6 +21,7 @@ namespace Avalonia.Android private readonly ViewImpl _view; private IDisposable? _timerSubscription; + private bool _surfaceCreated; public AvaloniaView(Context context) : base(context) { @@ -32,6 +33,18 @@ namespace Avalonia.Android this.SetBackgroundColor(global::Android.Graphics.Color.Transparent); OnConfigurationChanged(); + + _view.InternalView.SurfaceWindowCreated += InternalView_SurfaceWindowCreated; + } + + private void InternalView_SurfaceWindowCreated(object? sender, EventArgs e) + { + _surfaceCreated = true; + + if (Visibility == ViewStates.Visible) + { + OnVisibilityChanged(true); + } } internal TopLevelImpl TopLevelImpl => _view; @@ -43,9 +56,10 @@ namespace Avalonia.Android set { _root.Content = value; } } - protected override void Dispose(bool disposing) + internal new void Dispose() { - base.Dispose(disposing); + OnVisibilityChanged(false); + _surfaceCreated = false; _root?.Dispose(); _root = null!; } @@ -70,6 +84,8 @@ namespace Avalonia.Android internal void OnVisibilityChanged(bool isVisible) { + if (_root == null || !_surfaceCreated) + return; if (isVisible && _timerSubscription == null) { if (AvaloniaLocator.Current.GetService() is ChoreographerTimer timer) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs index 0d9206f418..2ec255df19 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs @@ -13,9 +13,12 @@ namespace Avalonia.Android internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, INativePlatformHandleSurface { bool _invalidateQueued; + private bool _isDisposed; readonly object _lock = new object(); private readonly Handler _handler; + internal event EventHandler? SurfaceWindowCreated; + IntPtr IPlatformHandle.Handle => Holder?.Surface?.Handle is { } handle ? AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, handle) : default; @@ -39,7 +42,7 @@ namespace Avalonia.Android return; _handler.Post(() => { - if (Holder?.Surface?.IsValid != true) + if (_isDisposed || Holder?.Surface?.IsValid != true) return; try { @@ -53,6 +56,11 @@ namespace Avalonia.Android } } + internal new void Dispose() + { + _isDisposed = true; + } + public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) { Log.Info("AVALONIA", "Surface Changed"); @@ -62,6 +70,7 @@ namespace Avalonia.Android public void SurfaceCreated(ISurfaceHolder holder) { Log.Info("AVALONIA", "Surface Created"); + SurfaceWindowCreated?.Invoke(this, EventArgs.Empty); DoDraw(); }