Skip to content

Commit

Permalink
Merge branch 'master' into refactor-keycombination
Browse files Browse the repository at this point in the history
  • Loading branch information
bdach committed May 23, 2024
2 parents 8162563 + 11c2d23 commit 759c48e
Show file tree
Hide file tree
Showing 151 changed files with 7,539 additions and 4,733 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ jobs:

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: 1.21.9

- name: Install httpbin
run: go install github.com/mccutchen/go-httpbin/v2/cmd/go-httpbin@latest
Expand Down
11 changes: 11 additions & 0 deletions osu-framework.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -775,9 +775,19 @@ See the LICENCE file in the repository root for full licence text.
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=236f7aa5_002D7b06_002D43ca_002Dbf2a_002D9b31bfcff09a/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=2c62818f_002D621b_002D4425_002Dadc9_002D78611099bfcb/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Type parameters"&gt;&lt;ElementKinds&gt;&lt;Kind Name="TYPE_PARAMETER" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"&gt;&lt;ExtraRule Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=669e5282_002Dfb4b_002D4e90_002D91e7_002D07d269d04b60/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=76f79b1e_002Dece7_002D4df2_002Da322_002D1bd7fea25eb7/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local functions"&gt;&lt;ElementKinds&gt;&lt;Kind Name="LOCAL_FUNCTION" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=8b8504e3_002Df0be_002D4c14_002D9103_002Dc732f2bddc15/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Enum members"&gt;&lt;ElementKinds&gt;&lt;Kind Name="ENUM_MEMBER" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=9d1af99b_002Dbefe_002D48a4_002D9eb3_002D661384e29869/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private methods"&gt;&lt;ElementKinds&gt;&lt;Kind Name="ASYNC_METHOD" /&gt;&lt;Kind Name="METHOD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=9ffbe43b_002Dc610_002D411b_002D9839_002D1416a146d9b0/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public methods"&gt;&lt;ElementKinds&gt;&lt;Kind Name="ASYNC_METHOD" /&gt;&lt;Kind Name="METHOD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a4c2df6c_002Db202_002D48d5_002Db077_002De678cb548c25/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private properties"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PROPERTY" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a4f433b8_002Dabcd_002D4e55_002Da08f_002D82e78cef0f0c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local constants"&gt;&lt;ElementKinds&gt;&lt;Kind Name="LOCAL_CONSTANT" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=c873eafb_002Dd57f_002D481d_002D8c93_002D77f6863c2f88/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=fd562728_002Dc23d_002D417f_002Da19f_002D9d854247fbea/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public properties"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PROPERTY" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
Expand Down Expand Up @@ -843,6 +853,7 @@ See the LICENCE file in the repository root for full licence text.&#xD;
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UnitTesting/NUnitProvider/SetCurrentDirectoryTo/@EntryValue">TestFolder</s:String>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=28A2A5FC43E07C488A4BC7430879479E/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=28A2A5FC43E07C488A4BC7430879479E/Applicability/=Live/@EntryIndexedValue">True</s:Boolean>
Expand Down
31 changes: 0 additions & 31 deletions osu.Framework.Android/AndroidClipboard.cs

This file was deleted.

108 changes: 21 additions & 87 deletions osu.Framework.Android/AndroidGameActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Java.Lang;
using ManagedBass;
using osu.Framework.Bindables;
using Org.Libsdl.App;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Platform;
using Debug = System.Diagnostics.Debug;

namespace osu.Framework.Android
{
// since `ActivityAttribute` can't be inherited, the below is only provided as an illustrative example of how to setup an activity for best compatibility.
[Activity(ConfigurationChanges = DEFAULT_CONFIG_CHANGES, Exported = true, LaunchMode = DEFAULT_LAUNCH_MODE, MainLauncher = true)]
public abstract class AndroidGameActivity : Activity
public abstract class AndroidGameActivity : SDLActivity
{
protected const ConfigChanges DEFAULT_CONFIG_CHANGES = ConfigChanges.Keyboard
| ConfigChanges.KeyboardHidden
Expand All @@ -31,37 +32,24 @@ public abstract class AndroidGameActivity : Activity

protected const LaunchMode DEFAULT_LAUNCH_MODE = LaunchMode.SingleInstance;

protected abstract Game CreateGame();
internal static AndroidGameSurface Surface => (AndroidGameSurface)MSurface!;

/// <summary>
/// Whether this <see cref="AndroidGameActivity"/> is active (in the foreground).
/// </summary>
public BindableBool IsActive { get; } = new BindableBool();
private GameHost? host;

/// <summary>
/// The visibility flags for the system UI (status and navigation bars)
/// </summary>
public SystemUiFlags UIVisibilityFlags
{
#pragma warning disable 618 // SystemUiVisibility is deprecated
get => (SystemUiFlags)Window.AsNonNull().DecorView.SystemUiVisibility;
set
{
systemUiFlags = value;
Window.AsNonNull().DecorView.SystemUiVisibility = (StatusBarVisibility)value;
#pragma warning restore 618
}
}
protected abstract Game CreateGame();

private SystemUiFlags systemUiFlags;
protected override string[] GetLibraries() => new string[] { "SDL3" };

private AndroidGameView gameView = null!;
protected override SDLSurface CreateSDLSurface(Context? context) => new AndroidGameSurface(this, context);

public override void OnTrimMemory([GeneratedEnum] TrimMemory level)
protected override IRunnable CreateSDLMainRunnable() => new Runnable(() =>
{
base.OnTrimMemory(level);
gameView.Host?.Collect();
}
host = new AndroidGameHost(this);
host.Run(CreateGame());
if (!IsFinishing)
Finish();
});

protected override void OnCreate(Bundle? savedInstanceState)
{
Expand All @@ -75,82 +63,28 @@ protected override void OnCreate(Bundle? savedInstanceState)

base.OnCreate(savedInstanceState);

SetContentView(gameView = new AndroidGameView(this, CreateGame()));

UIVisibilityFlags = SystemUiFlags.LayoutFlags | SystemUiFlags.ImmersiveSticky | SystemUiFlags.HideNavigation | SystemUiFlags.Fullscreen;

// Firing up the on-screen keyboard (eg: interacting with textboxes) may cause the UI visibility flags to be altered thus showing the navigation bar and potentially the status bar
// This sets back the UI flags to hidden once the interaction with the on-screen keyboard has finished.
Window.AsNonNull().DecorView.SystemUiVisibilityChange += (_, e) =>
{
if ((SystemUiFlags)e.Visibility != systemUiFlags)
{
UIVisibilityFlags = systemUiFlags;
}
};

if (OperatingSystem.IsAndroidVersionAtLeast(28))
{
Window.AsNonNull().Attributes.AsNonNull().LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges;
}
}

gameView.HostStarted += host =>
{
host.AllowScreenSuspension.Result.BindValueChanged(allow =>
{
RunOnUiThread(() =>
{
if (!allow.NewValue)
Window?.AddFlags(WindowManagerFlags.KeepScreenOn);
else
Window?.ClearFlags(WindowManagerFlags.KeepScreenOn);
});
}, true);
};
public override void OnTrimMemory(TrimMemory level)
{
base.OnTrimMemory(level);
host?.Collect();
}

protected override void OnStop()
{
base.OnStop();
gameView.Host?.Suspend();
Bass.Pause();
}

protected override void OnRestart()
{
base.OnRestart();
gameView.Host?.Resume();
Bass.Start();
}

public override void OnWindowFocusChanged(bool hasFocus)
{
base.OnWindowFocusChanged(hasFocus);
IsActive.Value = hasFocus;
}

public override void OnBackPressed()
{
// Avoid the default implementation that does close the app.
// This only happens when the back button could not be captured from OnKeyDown.
}

// On some devices and keyboard combinations the OnKeyDown event does not propagate the key event to the view.
// Here it is done manually to ensure that the keys actually land in the view.

public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent? e)
{
return gameView.OnKeyDown(keyCode, e);
}

public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent? e)
{
return gameView.OnKeyUp(keyCode, e);
}

public override bool OnKeyLongPress([GeneratedEnum] Keycode keyCode, KeyEvent? e)
{
return gameView.OnKeyLongPress(keyCode, e);
}
}
}
37 changes: 13 additions & 24 deletions osu.Framework.Android/AndroidGameHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,27 @@
using Android.Content;
using osu.Framework.Android.Graphics.Textures;
using osu.Framework.Android.Graphics.Video;
using osu.Framework.Android.Input;
using osu.Framework.Configuration;
using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Video;
using osu.Framework.Input;
using osu.Framework.Input.Handlers;
using osu.Framework.Input.Handlers.Midi;
using osu.Framework.IO.Stores;
using osu.Framework.Logging;
using osu.Framework.Platform;
using Uri = Android.Net.Uri;

namespace osu.Framework.Android
{
public class AndroidGameHost : OsuTKGameHost
public class AndroidGameHost : SDLGameHost
{
private readonly AndroidGameView gameView;
private readonly AndroidGameActivity activity;

public AndroidGameHost(AndroidGameView gameView)
public AndroidGameHost(AndroidGameActivity activity)
: base(string.Empty)
{
this.gameView = gameView;
this.activity = activity;
}

protected override void SetupConfig(IDictionary<FrameworkSetting, object> defaultOverrides)
Expand All @@ -42,28 +39,20 @@ protected override void SetupConfig(IDictionary<FrameworkSetting, object> defaul
base.SetupConfig(defaultOverrides);
}

protected override IWindow CreateWindow(GraphicsSurfaceType preferredSurface) => new AndroidGameWindow(gameView);
protected override IWindow CreateWindow(GraphicsSurfaceType preferredSurface) => new AndroidGameWindow(preferredSurface, Options.FriendlyGameName);

protected override Clipboard CreateClipboard() => new AndroidClipboard(gameView);
protected override void DrawFrame()
{
if (AndroidGameActivity.Surface.IsSurfaceReady)
base.DrawFrame();
}

public override bool CanExit => false;

public override bool CanSuspendToBackground => true;

public override bool OnScreenKeyboardOverlapsGameWindow => true;

protected override TextInputSource CreateTextInput() => new AndroidTextInput(gameView);

protected override IEnumerable<InputHandler> CreateAvailableInputHandlers() =>
new InputHandler[]
{
new AndroidMouseHandler(gameView),
new AndroidKeyboardHandler(gameView),
new AndroidTouchHandler(gameView),
new AndroidJoystickHandler(gameView),
new MidiHandler()
};

public override string InitialFileSelectorPath => @"/sdcard";

public override Storage GetStorage(string path) => new AndroidStorage(path, this);
Expand All @@ -87,7 +76,7 @@ public override void OpenUrlExternally(string url)
{
// Recommended way to open URLs on Android 11+
// https://developer.android.com/training/package-visibility/use-cases#open-urls-browser-or-other-app
gameView.Activity.StartActivity(intent);
activity.StartActivity(intent);
}
}
catch (Exception ex)
Expand All @@ -104,7 +93,7 @@ public override VideoDecoder CreateVideoDecoder(Stream stream)

public override bool SuspendToBackground()
{
return gameView.Activity.MoveTaskToBack(true);
return activity.MoveTaskToBack(true);
}
}
}
Loading

0 comments on commit 759c48e

Please sign in to comment.