Skip to content

Commit

Permalink
Merge branch 'master' into remove-ios-ci-workaround
Browse files Browse the repository at this point in the history
  • Loading branch information
peppy authored Jul 1, 2022
2 parents 35c4ee3 + 5612aa9 commit d444b72
Show file tree
Hide file tree
Showing 19 changed files with 518 additions and 258 deletions.
49 changes: 48 additions & 1 deletion osu.Framework.Android/AndroidGameView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ public bool PointerCapture

private readonly Game game;

private InputMethodManager inputMethodManager;

/// <summary>
/// Whether <see cref="AndroidTextInput"/> is active.
/// </summary>
private bool textInputActive;

public AndroidGameView(AndroidGameActivity activity, Game game)
: base(activity)
{
Expand Down Expand Up @@ -94,6 +101,11 @@ private void init()
// this needs to happen in the constructor
Focusable = true;
FocusableInTouchMode = true;

// disable ugly green border when view is focused via hardware keyboard/mouse.
DefaultFocusHighlightEnabled = false;

inputMethodManager = Activity.GetSystemService(Context.InputMethodService) as InputMethodManager;
}

protected override void CreateFrameBuffer()
Expand Down Expand Up @@ -128,6 +140,13 @@ public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e)

default:
KeyDown?.Invoke(keyCode, e);

// Releasing backspace on a physical keyboard when text input is active will not send a key up event.
// Manually send one to prevent the key from getting stuck.
// This does mean that key repeat is handled by the OS, instead of by the usual `InputManager` handling.
if (keyCode == Keycode.Del && e.IsFromSource(InputSourceType.Keyboard) && textInputActive)
KeyUp?.Invoke(Keycode.Del, new KeyEvent(e.DownTime, e.EventTime, KeyEventActions.Up, Keycode.Del, 0, e.MetaState, e.DeviceId, e.ScanCode, e.Flags, e.Source));

return true;
}
}
Expand Down Expand Up @@ -235,15 +254,43 @@ private void updateSafeArea()
};
}

public override bool OnCheckIsTextEditor() => true;
public override bool OnCheckIsTextEditor() => textInputActive;

/// <returns><c>null</c> to disable input methods</returns>
public override IInputConnection OnCreateInputConnection(EditorInfo outAttrs)
{
// Properly disable native input methods so that the software keyboard doesn't unexpectedly open.
// Eg. when pressing keys on a hardware keyboard.
if (!textInputActive)
return null;

outAttrs.ImeOptions = ImeFlags.NoExtractUi | ImeFlags.NoFullscreen;
outAttrs.InputType = InputTypes.TextVariationVisiblePassword | InputTypes.TextFlagNoSuggestions;
return new AndroidInputConnection(this, true);
}

internal void StartTextInput()
{
textInputActive = true;
Activity.RunOnUiThread(() =>
{
inputMethodManager.RestartInput(this); // this syncs the Android input method state with `OnCreateInputConnection()`.
RequestFocus();
inputMethodManager?.ShowSoftInput(this, 0);
});
}

internal void StopTextInput()
{
textInputActive = false;
Activity.RunOnUiThread(() =>
{
inputMethodManager.RestartInput(this);
inputMethodManager?.HideSoftInputFromWindow(WindowToken, HideSoftInputFlags.None);
ClearFocus();
});
}

public override void SwapBuffers()
{
try
Expand Down
28 changes: 4 additions & 24 deletions osu.Framework.Android/Input/AndroidTextInput.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using Android.Content;
using Android.Views;
using Android.Views.InputMethods;
using osu.Framework.Input;

namespace osu.Framework.Android.Input
{
public class AndroidTextInput : TextInputSource
internal class AndroidTextInput : TextInputSource
{
private readonly AndroidGameView view;
private readonly InputMethodManager inputMethodManager;

public AndroidTextInput(AndroidGameView view)
{
this.view = view;
inputMethodManager = view.Activity.GetSystemService(Context.InputMethodService) as InputMethodManager;
}

private void commitText(string text)
Expand All @@ -36,33 +30,19 @@ protected override void ActivateTextInput(bool allowIme)
{
view.KeyDown += keyDown;
view.CommitText += commitText;

view.Activity.RunOnUiThread(() =>
{
view.RequestFocus();
inputMethodManager?.ShowSoftInput(view, 0);
});
view.StartTextInput();
}

protected override void EnsureTextInputActivated(bool allowIme)
{
view.Activity.RunOnUiThread(() =>
{
view.RequestFocus();
inputMethodManager?.ShowSoftInput(view, 0);
});
view.StartTextInput();
}

protected override void DeactivateTextInput()
{
view.KeyDown -= keyDown;
view.CommitText -= commitText;

view.Activity.RunOnUiThread(() =>
{
inputMethodManager?.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
});
view.StopTextInput();
}
}
}
11 changes: 10 additions & 1 deletion osu.Framework.Benchmarks/BenchmarkTransformUpdate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace osu.Framework.Benchmarks
public class BenchmarkTransformUpdate : BenchmarkTest
{
private TestBox target;
private TestBox targetNoTransforms;

public override void SetUp()
{
Expand All @@ -23,7 +24,8 @@ public override void SetUp()

ManualClock clock;

target = new TestBox { Clock = new FramedClock(clock = new ManualClock()) };
targetNoTransforms = new TestBox { Clock = new FramedClock(clock = new ManualClock()) };
target = new TestBox { Clock = new FramedClock(clock) };

// transform one target member over a long period
target.RotateTo(360, transforms_count * 2);
Expand All @@ -36,6 +38,13 @@ public override void SetUp()
target.Clock.ProcessFrame();
}

[Benchmark]
public void UpdateTransformsWithNonePresent()
{
for (int i = 0; i < 10000; i++)
targetNoTransforms.UpdateTransforms();
}

[Benchmark]
public void UpdateTransformsWithManyPresent()
{
Expand Down
102 changes: 102 additions & 0 deletions osu.Framework.Tests/Graphics/TripleBufferTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions;

namespace osu.Framework.Tests.Graphics
{
[TestFixture]
public class TripleBufferTest
{
[Test]
public void TestWriteOnly()
{
var tripleBuffer = new TripleBuffer<TestObject>();

for (int i = 0; i < 1000; i++)
{
using (tripleBuffer.GetForWrite())
{
}
}
}

[Test]
public void TestReadOnly()
{
var tripleBuffer = new TripleBuffer<TestObject>();

using (var buffer = tripleBuffer.GetForRead())
Assert.That(buffer, Is.Null);
}

[Test]
public void TestWriteThenRead()
{
var tripleBuffer = new TripleBuffer<TestObject>();

for (int i = 0; i < 1000; i++)
{
var obj = new TestObject(i);

using (var buffer = tripleBuffer.GetForWrite())
buffer.Object = obj;

using (var buffer = tripleBuffer.GetForRead())
Assert.That(buffer?.Object, Is.EqualTo(obj));
}

using (var buffer = tripleBuffer.GetForRead())
Assert.That(buffer, Is.Null);
}

[Test]
public void TestReadSaturated()
{
var tripleBuffer = new TripleBuffer<TestObject>();

for (int i = 0; i < 10; i++)
{
var obj = new TestObject(i);
ManualResetEventSlim resetEventSlim = new ManualResetEventSlim();

var readTask = Task.Factory.StartNew(() =>
{
resetEventSlim.Set();
using (var buffer = tripleBuffer.GetForRead())
Assert.That(buffer?.Object, Is.EqualTo(obj));
}, TaskCreationOptions.LongRunning);

Task.Factory.StartNew(() =>
{
resetEventSlim.Wait(1000);
Thread.Sleep(10);

using (var buffer = tripleBuffer.GetForWrite())
buffer.Object = obj;
}, TaskCreationOptions.LongRunning);

readTask.WaitSafely();
}
}

private class TestObject
{
private readonly int i;

public TestObject(int i)
{
this.i = i;
}

public override string ToString()
{
return $"{base.ToString()} {i}";
}
}
}
}
29 changes: 28 additions & 1 deletion osu.Framework.Tests/Localisation/LocalisationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,32 @@ public void TestConfigSettingRetainedWhenAddingNewLanguage()
Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_JA_JP, localisedText.Value);
}

[Test]
public void TestConfigSettingRetainedWhenAddingLocaleMappings()
{
config.SetValue(FrameworkSetting.Locale, "ja-JP");

// ensure that adding a new language which doesn't match the user's choice doesn't cause the configuration value to get reset.
manager.AddLocaleMappings(new[]
{
new LocaleMapping("po", new FakeStorage("po-OP")),
new LocaleMapping("wa", new FakeStorage("wa-NG"))
});

Assert.AreEqual("ja-JP", config.Get<string>(FrameworkSetting.Locale));

var localisedText = manager.GetLocalisedBindableString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN));
Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_EN, localisedText.Value);

// ensure that if the user's selection is added in a further AddLanguage call, the manager correctly translates strings.
manager.AddLocaleMappings(new[]
{
new LocaleMapping("ja-JP", new FakeStorage("ja-JP"))
});

Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_JA_JP, localisedText.Value);
}

[Test]
public void TestNotLocalised()
{
Expand Down Expand Up @@ -122,7 +148,8 @@ public void TestFormattedInterpolation()

string expectedResult = string.Format(FakeStorage.LOCALISABLE_FORMAT_STRING_JA, arg_0);

var formattedText = manager.GetLocalisedBindableString(new TranslatableString(FakeStorage.LOCALISABLE_FORMAT_STRING_EN, interpolation: $"The {arg_0} fallback should only matches argument count"));
var formattedText = manager.GetLocalisedBindableString(new TranslatableString(FakeStorage.LOCALISABLE_FORMAT_STRING_EN,
interpolation: $"The {arg_0} fallback should only matches argument count"));

Assert.AreEqual(expectedResult, formattedText.Value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,7 @@ protected override bool OnClick(ClickEvent e)
return true;
}

return true;
}

protected override bool OnMouseDown(MouseDownEvent e)
{
base.OnMouseDown(e);
return true;
return false;
}

protected override void PopIn()
Expand Down
15 changes: 10 additions & 5 deletions osu.Framework/Allocation/ObjectUsage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@ public class ObjectUsage<T> : IDisposable
where T : class
{
public T Object;
public int Index;

public long FrameId;
public UsageType Usage;

internal Action<ObjectUsage<T>, UsageType> Finish;
public readonly int Index;

public UsageType Usage;
private readonly Action<ObjectUsage<T>> finish;

public ObjectUsage(int index, Action<ObjectUsage<T>> finish)
{
Index = index;
this.finish = finish;
}

public void Dispose()
{
Finish?.Invoke(this, Usage);
finish?.Invoke(this);
}
}

Expand Down
Loading

0 comments on commit d444b72

Please sign in to comment.