diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 7921b608b6..191bdf32d0 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -1,6 +1,6 @@  - net7.0-android + net8.0-android 21 Exe enable diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index fce568b15e..dcc2066149 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/samples/ControlCatalog.Android/MainActivity.cs @@ -4,11 +4,16 @@ using Avalonia; using Avalonia.Android; using static Android.Content.Intent; +// leanback and touchscreen are required for the Android TV. +[assembly: UsesFeature("android.software.leanback", Required = false)] +[assembly: UsesFeature("android.hardware.touchscreen", Required = false)] + namespace ControlCatalog.Android { [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, Exported = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] - // IntentFilter are here to test IActivatableApplicationLifetime - [IntentFilter(new [] { ActionView }, Categories = new [] { CategoryDefault, CategoryBrowsable }, DataScheme = "avln" )] + // CategoryBrowsable and DataScheme are required for Protocol activation. + // CategoryLeanbackLauncher is required for Android TV. + [IntentFilter(new [] { ActionView }, Categories = new [] { CategoryDefault, CategoryBrowsable, CategoryLeanbackLauncher }, DataScheme = "avln" )] public class MainActivity : AvaloniaMainActivity { protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) diff --git a/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs b/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs index a416e05b52..08d71fc67c 100644 --- a/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs +++ b/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs @@ -31,10 +31,6 @@ namespace Avalonia.Android.Platform.Input { Keycode.PageDown, Key.PageDown }, { Keycode.MoveEnd, Key.End }, { Keycode.MoveHome, Key.Home }, - { Keycode.DpadLeft, Key.Left }, - { Keycode.DpadUp, Key.Up }, - { Keycode.DpadRight, Key.Right }, - { Keycode.DpadDown, Key.Down }, // { Keycode.ButtonSelect?, Key.Select }, // { Keycode.print?, Key.Print }, //{ Keycode.execute?, Key.Execute }, @@ -209,7 +205,15 @@ namespace Avalonia.Android.Platform.Input //{ Keycode.?, Key.DbeEnterDialogConversionMode } //{ Keycode.?, Key.OemClear } //{ Keycode.?, Key.DeadCharProcessed } - { Keycode.Backslash, Key.OemBackslash } + { Keycode.Backslash, Key.OemBackslash }, + + // Loosely mapping DPad keys to Avalonia keys + { Keycode.Back, Key.Escape }, + { Keycode.DpadCenter, Key.Space }, + { Keycode.DpadLeft, Key.Left }, + { Keycode.DpadUp, Key.Up }, + { Keycode.DpadRight, Key.Right }, + { Keycode.DpadDown, Key.Down } }; internal static Key ConvertKey(Keycode key) diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index eed8069a93..84f7757197 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs @@ -129,15 +129,20 @@ namespace Avalonia.Android.Platform.Specific.Helpers private KeyDeviceType GetKeyDeviceType(KeyEvent e) { var source = e.Device?.Sources ?? InputSourceType.Unknown; - if (source is InputSourceType.Joystick or - InputSourceType.ClassJoystick or - InputSourceType.Gamepad) - return KeyDeviceType.Gamepad; - if (source == InputSourceType.Dpad && e.Device?.KeyboardType == InputKeyboardType.NonAlphabetic) + // Remote controller reports itself as "DPad | Keyboard", which is confusing, + // so we need to double-check KeyboardType as well. + + if (source.HasAnyFlag(InputSourceType.Dpad) + && e.Device?.KeyboardType == InputKeyboardType.NonAlphabetic) return KeyDeviceType.Remote; - return KeyDeviceType.Keyboard; + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags - it IS flags enum under the hood. + if (source.HasAnyFlag(InputSourceType.Joystick | InputSourceType.Gamepad)) + return KeyDeviceType.Gamepad; + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + + return KeyDeviceType.Keyboard; // fallback to the keyboard, if unknown. } public void Dispose()