From f22b688a8c6624a69750d4ce90d5bff8cc60439e Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Sat, 29 Jan 2022 07:10:39 +0000 Subject: [PATCH 1/3] support configuration changes --- .../ControlCatalog.Android.csproj | 16 ++++++++- .../ControlCatalog.Android/MainActivity.cs | 3 +- .../Resources/values/styles.xml | 2 +- .../Avalonia.Android/Avalonia.Android.csproj | 9 +++++ .../Avalonia.Android/AvaloniaActivity.cs | 36 ++++++++++++++----- .../Avalonia.Android/AvaloniaViewModel.cs | 11 ++++++ 6 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 src/Android/Avalonia.Android/AvaloniaViewModel.cs diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 1654d20c80b..516acfe4b92 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -21,9 +21,23 @@ True - True + False True + + + False + False + + + + True + + + + + + diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index 137f280e439..b02083c39d0 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/samples/ControlCatalog.Android/MainActivity.cs @@ -5,7 +5,7 @@ namespace ControlCatalog.Android { - [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)] + [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] public class MainActivity : AvaloniaActivity { protected override void OnCreate(Bundle? savedInstanceState) @@ -16,4 +16,3 @@ protected override void OnCreate(Bundle? savedInstanceState) } } } - diff --git a/samples/ControlCatalog.Android/Resources/values/styles.xml b/samples/ControlCatalog.Android/Resources/values/styles.xml index e017b6facf9..2759d2904a3 100644 --- a/samples/ControlCatalog.Android/Resources/values/styles.xml +++ b/samples/ControlCatalog.Android/Resources/values/styles.xml @@ -4,7 +4,7 @@ - diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index b774938a1d9..6e0b6156262 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -7,6 +7,15 @@ + + + + + + + False + False + diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs index 3c9f373a661..fbadc257e22 100644 --- a/src/Android/Avalonia.Android/AvaloniaActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -1,35 +1,55 @@ using Android.App; using Android.OS; using Android.Views; +using Android.Content.PM; +using AndroidX.AppCompat.App; +using Android.Content.Res; +using AndroidX.Lifecycle; namespace Avalonia.Android { - public abstract class AvaloniaActivity : Activity + public abstract class AvaloniaActivity : AppCompatActivity { internal AvaloniaView View; - object _content; - + internal AvaloniaViewModel _viewModel; protected override void OnCreate(Bundle savedInstanceState) { View = new AvaloniaView(this); - if (_content != null) - View.Content = _content; SetContentView(View); + + _viewModel = new ViewModelProvider(this).Get(Java.Lang.Class.FromType(typeof(AvaloniaViewModel))) as AvaloniaViewModel; + + if (_viewModel.Content != null) + { + View.Content = _viewModel.Content; + } + base.OnCreate(savedInstanceState); } - public object Content { get { - return _content; + return _viewModel.Content; } set { - _content = value; + _viewModel.Content = value; if (View != null) View.Content = value; } } + + public override void OnConfigurationChanged(Configuration newConfig) + { + base.OnConfigurationChanged(newConfig); + } + + protected override void OnDestroy() + { + View.Content = null; + + base.OnDestroy(); + } } } diff --git a/src/Android/Avalonia.Android/AvaloniaViewModel.cs b/src/Android/Avalonia.Android/AvaloniaViewModel.cs new file mode 100644 index 00000000000..1b2c00987a2 --- /dev/null +++ b/src/Android/Avalonia.Android/AvaloniaViewModel.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Avalonia.Android +{ + internal class AvaloniaViewModel : AndroidX.Lifecycle.ViewModel + { + public object Content { get; set; } + } +} From 76cd4386f1dfc71bcaecaa64927d912df8df8634 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Sat, 29 Jan 2022 10:49:29 +0000 Subject: [PATCH 2/3] use pdb files for debug on android projects. do not use full screen keyboard when landscape --- Avalonia.sln | 4 +- .../Avalonia.Android/AndroidInputMethod.cs | 4 +- .../Avalonia.Android/Avalonia.Android.csproj | 5 +- .../Resources/AboutResources.txt | 50 ------------------- .../Resources/Values/Strings.xml | 6 --- ...oardListner.cs => SoftKeyboardListener.cs} | 4 +- .../Avalonia.AndroidTestApplication.csproj | 8 +++ .../MainActivity.cs | 2 + 8 files changed, 18 insertions(+), 65 deletions(-) delete mode 100644 src/Android/Avalonia.Android/Resources/AboutResources.txt delete mode 100644 src/Android/Avalonia.Android/Resources/Values/Strings.xml rename src/Android/Avalonia.Android/{SoftKeyboardListner.cs => SoftKeyboardListener.cs} (89%) diff --git a/Avalonia.sln b/Avalonia.sln index f1bdfdbbc39..c3e86734d81 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -95,7 +95,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog", "samples\C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{52F55355-D120-42AC-8116-8410A7D602FA}" EndProject @@ -1105,7 +1105,7 @@ Global {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhone.Build.0 = AppStore|iPhone {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|Any CPU.ActiveCfg = Debug|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.ActiveCfg = Debug|iPhone {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.Build.0 = Debug|iPhone {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs index 7e49cb5dfaa..b6491a5890b 100644 --- a/src/Android/Avalonia.Android/AndroidInputMethod.cs +++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs @@ -25,7 +25,7 @@ public AndroidInputMethod(TView host) _host.Focusable = true; _host.FocusableInTouchMode = true; - _host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListner(_host)); + _host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListener(_host)); } public void Reset() @@ -83,6 +83,8 @@ public void SetOptions(TextInputOptionsQueryEventArgs options) if (options.Multiline) outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagMultiLine; + + outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi; }); //_inputElement.PointerReleased += RestoreSoftKeyboard; diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 6e0b6156262..6393ef34055 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -4,6 +4,7 @@ 21 true true + portable @@ -14,8 +15,4 @@ - - False - False - diff --git a/src/Android/Avalonia.Android/Resources/AboutResources.txt b/src/Android/Avalonia.Android/Resources/AboutResources.txt deleted file mode 100644 index 194ae28a59b..00000000000 --- a/src/Android/Avalonia.Android/Resources/AboutResources.txt +++ /dev/null @@ -1,50 +0,0 @@ -Images, layout descriptions, binary blobs and string dictionaries can be included -in your application as resource files. Various Android APIs are designed to -operate on the resource IDs instead of dealing with images, strings or binary blobs -directly. - -For example, a sample Android app that contains a user interface layout (main.xml), -an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) -would keep its resources in the "Resources" directory of the application: - -Resources/ - drawable-hdpi/ - icon.png - - drawable-ldpi/ - icon.png - - drawable-mdpi/ - icon.png - - layout/ - main.xml - - values/ - strings.xml - -In order to get the build system to recognize Android resources, set the build action to -"AndroidResource". The native Android APIs do not operate directly with filenames, but -instead operate on resource IDs. When you compile an Android application that uses resources, -the build system will package the resources for distribution and generate a class called -"Resource" that contains the tokens for each one of the resources included. For example, -for the above Resources layout, this is what the Resource class would expose: - -public class Resource { - public class drawable { - public const int icon = 0x123; - } - - public class layout { - public const int main = 0x456; - } - - public class strings { - public const int first_string = 0xabc; - public const int second_string = 0xbcd; - } -} - -You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main -to reference the layout/main.xml file, or Resource.strings.first_string to reference the first -string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Resources/Values/Strings.xml b/src/Android/Avalonia.Android/Resources/Values/Strings.xml deleted file mode 100644 index 3823c6f4c67..00000000000 --- a/src/Android/Avalonia.Android/Resources/Values/Strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - Hello World, Click Me! - $projectname$ - \ No newline at end of file diff --git a/src/Android/Avalonia.Android/SoftKeyboardListner.cs b/src/Android/Avalonia.Android/SoftKeyboardListener.cs similarity index 89% rename from src/Android/Avalonia.Android/SoftKeyboardListner.cs rename to src/Android/Avalonia.Android/SoftKeyboardListener.cs index df658f63148..5e996639ed8 100644 --- a/src/Android/Avalonia.Android/SoftKeyboardListner.cs +++ b/src/Android/Avalonia.Android/SoftKeyboardListener.cs @@ -9,7 +9,7 @@ namespace Avalonia.Android { - class SoftKeyboardListner : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener + class SoftKeyboardListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener { private const int DefaultKeyboardHeightDP = 100; private static readonly int EstimatedKeyboardDP = DefaultKeyboardHeightDP + (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop ? 48 : 0); @@ -17,7 +17,7 @@ class SoftKeyboardListner : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutLi private readonly View _host; private bool _wasKeyboard; - public SoftKeyboardListner(View view) + public SoftKeyboardListener(View view) { _host = view; } diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj index f1e23798534..8cb7aa1cfda 100644 --- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj +++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj @@ -9,6 +9,7 @@ 1.0 apk true + portable @@ -21,6 +22,13 @@ + + True + + + + True + diff --git a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs index 5f33cadf2e5..471b982d9e2 100644 --- a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs +++ b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs @@ -14,6 +14,8 @@ namespace Avalonia.AndroidTestApplication [Activity(Label = "Main", MainLauncher = true, Icon = "@drawable/icon", + Theme = "@style/Theme.AppCompat.NoActionBar", + ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, LaunchMode = LaunchMode.SingleInstance/*, ScreenOrientation = ScreenOrientation.Landscape*/)] public class MainBaseActivity : AvaloniaActivity From ef5851f123fb8a4b6185352da1a37fe6d1942029 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Thu, 3 Feb 2022 20:48:47 +0000 Subject: [PATCH 3/3] fix item repeater page crash --- samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs index 9e898c45369..6f0f8fcde0c 100644 --- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs +++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs @@ -111,7 +111,7 @@ private void LayoutChanged(object sender, SelectionChangedEventArgs e) private void ScrollTo(int index) { System.Diagnostics.Debug.WriteLine("Scroll to " + index); - var layoutManager = ((Window)this.GetVisualRoot()).LayoutManager; + var layoutManager = ((TopLevel)VisualRoot).LayoutManager; var element = _repeater.GetOrCreateElement(index); layoutManager.ExecuteLayoutPass(); element.BringIntoView();