diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
index fa29610b18..41d6329d26 100644
--- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
+++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
@@ -29,7 +29,7 @@
4
True
None
- False
+ True
False
False
armeabi;armeabi-v7a;x86
@@ -112,10 +112,6 @@
{7062ae20-5dcc-4442-9645-8195bdece63e}
Avalonia.Diagnostics
-
- {4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}
- Avalonia.DotNetFrameworkRuntime
-
{5fb2b005-0a7f-4dad-add4-3ed01444e63d}
Avalonia.HtmlRenderer
diff --git a/src/Android/Avalonia.Android/ActivityTracker.cs b/src/Android/Avalonia.Android/ActivityTracker.cs
new file mode 100644
index 0000000000..2ad1d9e361
--- /dev/null
+++ b/src/Android/Avalonia.Android/ActivityTracker.cs
@@ -0,0 +1,47 @@
+using Android.App;
+using Android.OS;
+
+namespace Avalonia.Android
+{
+ internal class ActivityTracker : Java.Lang.Object, global::Android.App.Application.IActivityLifecycleCallbacks
+ {
+ public static Activity Current { get; private set; }
+ public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
+ {
+ Current = activity;
+ }
+
+ public void OnActivityDestroyed(Activity activity)
+ {
+ if (Current == activity)
+ Current = null;
+ }
+
+ public void OnActivityPaused(Activity activity)
+ {
+ if (Current == activity)
+ Current = null;
+ }
+
+ public void OnActivityResumed(Activity activity)
+ {
+ Current = activity;
+ }
+
+ public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
+ {
+ Current = activity;
+ }
+
+ public void OnActivityStarted(Activity activity)
+ {
+ Current = activity;
+ }
+
+ public void OnActivityStopped(Activity activity)
+ {
+ if (Current == activity)
+ Current = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs
index 5b3170a0c7..2089359c26 100644
--- a/src/Android/Avalonia.Android/AndroidPlatform.cs
+++ b/src/Android/Avalonia.Android/AndroidPlatform.cs
@@ -62,6 +62,8 @@ namespace Avalonia.Android
.Bind().ToConstant(new AssetLoader(app.GetType().Assembly));
SkiaPlatform.Initialize();
+ ((global::Android.App.Application) global::Android.App.Application.Context.ApplicationContext)
+ .RegisterActivityLifecycleCallbacks(new ActivityTracker());
}
public IWindowImpl CreateWindow()
@@ -76,7 +78,7 @@ namespace Avalonia.Android
public IPopupImpl CreatePopup()
{
- throw new NotImplementedException();
+ return new PopupImpl();
}
}
}
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/AppBuilder.cs b/src/Android/Avalonia.Android/AppBuilder.cs
new file mode 100644
index 0000000000..6078e3bb98
--- /dev/null
+++ b/src/Android/Avalonia.Android/AppBuilder.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Avalonia.Controls;
+using Avalonia.Platform;
+using Avalonia.Shared.PlatformSupport;
+
+namespace Avalonia
+{
+ public sealed class AppBuilder : AppBuilderBase
+ {
+ public AppBuilder() : base(new StandardRuntimePlatform(),
+ builder => StandardRuntimePlatformServices.Register(builder.Instance?.GetType()?.Assembly))
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj
index 0dfab3f518..3ee2f5af64 100644
--- a/src/Android/Avalonia.Android/Avalonia.Android.csproj
+++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj
@@ -61,8 +61,10 @@
+
+
@@ -72,6 +74,7 @@
+
diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs
index a9b04c882b..21ce555086 100644
--- a/src/Android/Avalonia.Android/AvaloniaActivity.cs
+++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs
@@ -14,16 +14,17 @@ namespace Avalonia.Android
{
public abstract class AvaloniaActivity : Activity
{
- AvaloniaView _view;
+
+ internal AvaloniaView View;
object _content;
protected override void OnCreate(Bundle savedInstanceState)
{
RequestWindowFeature(WindowFeatures.NoTitle);
- _view = new AvaloniaView(this);
+ View = new AvaloniaView(this);
if(_content != null)
- _view.Content = _content;
- SetContentView(_view);
+ View.Content = _content;
+ SetContentView(View);
TakeKeyEvents(true);
base.OnCreate(savedInstanceState);
}
@@ -37,14 +38,14 @@ namespace Avalonia.Android
set
{
_content = value;
- if (_view != null)
- _view.Content = value;
+ if (View != null)
+ View.Content = value;
}
}
public override bool DispatchKeyEvent(KeyEvent e)
{
- return _view.DispatchKeyEvent(e);
+ return View.DispatchKeyEvent(e);
}
}
}
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs
index 71eea14a1d..6c4274a6e4 100644
--- a/src/Android/Avalonia.Android/AvaloniaView.cs
+++ b/src/Android/Avalonia.Android/AvaloniaView.cs
@@ -10,6 +10,7 @@ using Android.Runtime;
using Android.Views;
using Android.Widget;
using Avalonia.Android.Platform.SkiaPlatform;
+using Avalonia.Controls;
using Avalonia.Controls.Embedding;
using Avalonia.Platform;
@@ -23,7 +24,7 @@ namespace Avalonia.Android
public AvaloniaView(Context context) : base(context)
{
_view = new ViewImpl(context);
- AddView(_view);
+ AddView(_view.View);
_root = new EmbeddableControlRoot(_view);
_root.Prepare();
}
@@ -36,7 +37,7 @@ namespace Avalonia.Android
public override bool DispatchKeyEvent(KeyEvent e)
{
- return _view.DispatchKeyEvent(e);
+ return _view.View.DispatchKeyEvent(e);
}
class ViewImpl : TopLevelImpl, IEmbeddableWindowImpl
@@ -45,8 +46,8 @@ namespace Avalonia.Android
public ViewImpl(Context context) : base(context)
{
- Focusable = true;
- FocusChange += ViewImpl_FocusChange;
+ View.Focusable = true;
+ View.FocusChange += ViewImpl_FocusChange;
}
private void ViewImpl_FocusChange(object sender, FocusChangeEventArgs e)
@@ -54,6 +55,15 @@ namespace Avalonia.Android
if(!e.HasFocus)
LostFocus?.Invoke();
}
+
+ protected override void OnResized(Size size)
+ {
+ MaxClientSize = size;
+ base.OnResized(size);
+ }
+
+ public WindowState WindowState { get; set; }
+ public IDisposable ShowDialog() => null;
}
}
}
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
index 982c79560b..55e729f5a2 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
@@ -12,7 +12,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public AndroidFramebuffer(Surface surface)
{
+ if(surface == null)
+ throw new ArgumentNullException(nameof(surface));
_window = ANativeWindow_fromSurface(JNIEnv.Handle, surface.Handle);
+ if (_window == IntPtr.Zero)
+ throw new Exception("Unable to obtain ANativeWindow");
ANativeWindow_Buffer buffer;
var rc = new ARect()
{
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
index 2213ebddcc..d2d5909815 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
@@ -18,14 +18,13 @@ namespace Avalonia.Android
{
public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle
{
- private readonly Context _context;
bool _invalidateQueued;
readonly object _lock = new object();
private readonly Handler _handler;
+
public InvalidationAwareSurfaceView(Context context) : base(context)
{
- _context = context;
Holder.AddCallback(this);
_handler = new Handler(context.MainLooper);
}
@@ -38,13 +37,11 @@ namespace Avalonia.Android
return;
_handler.Post(() =>
{
- lock (_lock)
- {
- _invalidateQueued = false;
- }
+ if (Holder.Surface?.IsValid != true)
+ return;
try
{
- Draw();
+ DoDraw();
}
catch (Exception e)
{
@@ -67,20 +64,29 @@ namespace Avalonia.Android
public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{
Log.Info("AVALONIA", "Surface Changed");
- Draw();
+ DoDraw();
}
public void SurfaceCreated(ISurfaceHolder holder)
{
Log.Info("AVALONIA", "Surface Created");
- Draw();
+ DoDraw();
}
public void SurfaceDestroyed(ISurfaceHolder holder)
{
Log.Info("AVALONIA", "Surface Destroyed");
+
}
+ protected void DoDraw()
+ {
+ lock (_lock)
+ {
+ _invalidateQueued = false;
+ }
+ Draw();
+ }
protected abstract void Draw();
public string HandleDescriptor => "SurfaceView";
}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs
new file mode 100644
index 0000000000..e39ba2c121
--- /dev/null
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Android.App;
+using Android.Content;
+using Android.Graphics;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Avalonia.Platform;
+
+namespace Avalonia.Android.Platform.SkiaPlatform
+{
+ class PopupImpl : TopLevelImpl, IPopupImpl
+ {
+ private Point _position;
+ private bool _isAdded;
+ public PopupImpl() : base(ActivityTracker.Current, true)
+ {
+ }
+
+ private Size _clientSize = new Size(1, 1);
+ public override Size ClientSize
+ {
+ get { return base.ClientSize; }
+ set
+ {
+ if(View == null)
+ return;
+ _clientSize = value;
+ UpdateParams();
+ }
+ }
+
+ public override Point Position
+ {
+ get { return _position; }
+ set
+ {
+ _position = value;
+ PositionChanged?.Invoke(_position);
+ UpdateParams();
+ }
+ }
+
+ WindowManagerLayoutParams CreateParams() => new WindowManagerLayoutParams(0,
+ WindowManagerFlags.NotTouchModal, Format.Translucent)
+ {
+ Gravity = GravityFlags.Left | GravityFlags.Top,
+ WindowAnimations = 0,
+ X = (int) _position.X,
+ Y = (int) _position.Y,
+ Width = Math.Max(1, (int) _clientSize.Width),
+ Height = Math.Max(1, (int) _clientSize.Height)
+ };
+
+ void UpdateParams()
+ {
+ if (_isAdded)
+ ActivityTracker.Current?.WindowManager?.UpdateViewLayout(View, CreateParams());
+ }
+
+ public override void Show()
+ {
+ if (_isAdded)
+ return;
+ ActivityTracker.Current.WindowManager.AddView(View, CreateParams());
+ _isAdded = true;
+ }
+
+ public override void Hide()
+ {
+ if (_isAdded)
+ {
+ var wm = View.Context.ApplicationContext.GetSystemService(Context.WindowService)
+ .JavaCast();
+ wm.RemoveView(View);
+ _isAdded = false;
+ }
+ }
+
+ public override void Dispose()
+ {
+ Hide();
+ base.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 26d2b0aad9..d34981b964 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -9,42 +9,32 @@ using Avalonia.Input.Raw;
using Avalonia.Platform;
using System;
using System.Collections.Generic;
+using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Controls.Platform.Surfaces;
namespace Avalonia.Android.Platform.SkiaPlatform
{
- class TopLevelImpl : InvalidationAwareSurfaceView, IAndroidView, ITopLevelImpl,
- ISurfaceHolderCallback, IFramebufferPlatformSurface
+ class TopLevelImpl : IAndroidView, ITopLevelImpl, IFramebufferPlatformSurface
{
- protected AndroidKeyboardEventsHelper _keyboardHelper;
+ private readonly AndroidKeyboardEventsHelper _keyboardHelper;
+ private readonly AndroidTouchEventsHelper _touchHelper;
+ private ViewImpl _view;
- private AndroidTouchEventsHelper _touchHelper;
-
- public TopLevelImpl(Context context) : base(context)
+ public TopLevelImpl(Context context, bool placeOnTop = false)
{
+ _view = new ViewImpl(context, this, placeOnTop);
_keyboardHelper = new AndroidKeyboardEventsHelper(this);
- _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p));
+ _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot,
+ p => GetAvaloniaPointFromEvent(p));
- MaxClientSize = new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels);
- ClientSize = MaxClientSize;
+ MaxClientSize = new Size(_view.Resources.DisplayMetrics.WidthPixels,
+ _view.Resources.DisplayMetrics.HeightPixels);
}
-
- void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
- {
- var newSize = new Size(width, height);
- if (newSize != ClientSize)
- {
- MaxClientSize = newSize;
- ClientSize = newSize;
- Resized?.Invoke(ClientSize);
- }
- base.SurfaceChanged(holder, format, width, height);
- }
-
+
private bool _handleEvents;
public bool HandleEvents
@@ -56,17 +46,24 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_keyboardHelper.HandleEvents = _handleEvents;
}
}
- public WindowState WindowState
- {
- get { return WindowState.Normal; }
- set { }
- }
-
+
public virtual Point GetAvaloniaPointFromEvent(MotionEvent e) => new Point(e.GetX(), e.GetY());
public IInputRoot InputRoot { get; private set; }
- public Size ClientSize { get; set; }
+ public virtual Size ClientSize
+ {
+ get
+ {
+ if (_view == null)
+ return new Size(0, 0);
+ return new Size(_view.Width, _view.Height);
+ }
+ set
+ {
+
+ }
+ }
public Action Closed { get; set; }
@@ -74,7 +71,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Action Input { get; set; }
- public Size MaxClientSize { get; private set; }
+ public Size MaxClientSize { get; protected set; }
public Action Paint { get; set; }
@@ -84,21 +81,21 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Action PositionChanged { get; set; }
- public View View => this;
+ public View View => _view;
Action ITopLevelImpl.Activated { get; set; }
- IPlatformHandle ITopLevelImpl.Handle => this;
+ IPlatformHandle ITopLevelImpl.Handle => _view;
- public IEnumerable
-
- {4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}
- Avalonia.DotNetFrameworkRuntime
-
{5fb2b005-0a7f-4dad-add4-3ed01444e63d}
Avalonia.HtmlRenderer
diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs
index c53cca19d1..b098c270a5 100644
--- a/src/Avalonia.Controls/AppBuilderBase.cs
+++ b/src/Avalonia.Controls/AppBuilderBase.cs
@@ -60,10 +60,10 @@ namespace Avalonia.Controls
///
public Action BeforeStartCallback { get; private set; } = builder => { };
- protected AppBuilderBase(IRuntimePlatform platform, Action platformSevices)
+ protected AppBuilderBase(IRuntimePlatform platform, Action platformSevices)
{
RuntimePlatform = platform;
- RuntimePlatformServicesInitializer = platformSevices;
+ RuntimePlatformServicesInitializer = () => platformSevices((TAppBuilder)this);
}
///
diff --git a/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs b/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs
index 5a6b82573b..2b9b3083b1 100644
--- a/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs
+++ b/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
@@ -15,7 +16,9 @@ namespace Avalonia
/// Initializes a new instance of the class.
///
public AppBuilder()
- : base(new StandardRuntimePlatform(), () => StandardRuntimePlatformServices.Register())
+ : base(new StandardRuntimePlatform(),
+ builder => StandardRuntimePlatformServices.Register(builder.Instance?.GetType()
+ ?.GetTypeInfo().Assembly))
{
}
diff --git a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
index 3385e25d4f..f643bfe6e2 100644
--- a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
+++ b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
@@ -17,7 +17,8 @@ namespace Avalonia
/// Initializes a new instance of the class.
///
public AppBuilder()
- : base(new StandardRuntimePlatform(), () => StandardRuntimePlatformServices.Register())
+ : base(new StandardRuntimePlatform(),
+ builder => StandardRuntimePlatformServices.Register(builder.Instance?.GetType()?.Assembly))
{
}
diff --git a/src/Skia/Avalonia.Skia/BitmapImpl.cs b/src/Skia/Avalonia.Skia/BitmapImpl.cs
index 232f2721e1..7d99156a1d 100644
--- a/src/Skia/Avalonia.Skia/BitmapImpl.cs
+++ b/src/Skia/Avalonia.Skia/BitmapImpl.cs
@@ -63,7 +63,10 @@ namespace Avalonia.Skia
private static SKSurface CreateSurface(SKBitmap bitmap)
{
IntPtr length;
- return SKSurface.Create(bitmap.Info, bitmap.GetPixels(out length), bitmap.RowBytes);
+ var rv = SKSurface.Create(bitmap.Info, bitmap.GetPixels(out length), bitmap.RowBytes);
+ if (rv == null)
+ throw new Exception("Unable to create Skia surface");
+ return rv;
}
public BitmapDrawingContext(SKSurface surface) : base(surface.Canvas)