mirror of
https://github.com/osukey/osukey.git
synced 2025-04-29 10:47:22 +09:00
Send a warning notification if device is unplugged and low battery
- Uses Xamarin.Essentials in osu.Game.PlayerLoader to check battery level - Encapsulated battery checking in the public BatteryManager class so battery level and plugged in status can be accessed and edited in TestPlayerLoader - When checking battery level, catch NotImplementedException thrown by Xamarin.Essentials.Battery on non-mobile platforms - Added visual unit tests for battery notification To mock battery status and level, we had to define a batteryManager object in TestPlayerLoader and add a new function ResetPlayerWithBattery() Co-Authored-By: Marlina José <marlina@umich.edu>
This commit is contained in:
parent
544fff5af6
commit
0a6baf670e
@ -6,5 +6,6 @@
|
|||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
|
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||||
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!" android:icon="@drawable/lazer" />
|
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!" android:icon="@drawable/lazer" />
|
||||||
</manifest>
|
</manifest>
|
@ -93,6 +93,26 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive)));
|
LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the input manager child to a new test player loader container instance with a custom battery level
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="interactive">If the test player should behave like the production one.</param>
|
||||||
|
/// <param name="pluggedIn">If the player's device is plugged in.</param>
|
||||||
|
/// <param name="batteryLevel">A custom battery level for the test player.</param>
|
||||||
|
private void resetPlayerWithBattery(bool interactive, bool pluggedIn, double batteryLevel)
|
||||||
|
{
|
||||||
|
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning;
|
||||||
|
|
||||||
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
|
||||||
|
mod.ApplyToTrack(Beatmap.Value.Track);
|
||||||
|
|
||||||
|
loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive));
|
||||||
|
loader.batteryManager.ChargeLevel = batteryLevel;
|
||||||
|
loader.batteryManager.PluggedIn = pluggedIn;
|
||||||
|
LoadScreen(loader);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestEarlyExitBeforePlayerConstruction()
|
public void TestEarlyExitBeforePlayerConstruction()
|
||||||
{
|
{
|
||||||
@ -270,6 +290,32 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddUntilStep("wait for player load", () => player.IsLoaded);
|
AddUntilStep("wait for player load", () => player.IsLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(false, 1.0)] // not plugged in, full battery, no notification
|
||||||
|
[TestCase(false, 0.2)] // not plugged in, at warning level, no notification
|
||||||
|
[TestCase(true, 0.1)] // plugged in, charging, below warning level, no notification
|
||||||
|
[TestCase(false, 0.1)] // not plugged in, below warning level, notification
|
||||||
|
public void TestLowBatteryNotification(bool pluggedIn, double batteryLevel)
|
||||||
|
{
|
||||||
|
AddStep("reset notification lock", () => sessionStatics.GetBindable<bool>(Static.BatteryLowNotificationShownOnce).Value = false);
|
||||||
|
|
||||||
|
// mock phone on battery
|
||||||
|
AddStep("load player", () => resetPlayerWithBattery(false, pluggedIn, batteryLevel));
|
||||||
|
AddUntilStep("wait for player", () => player?.LoadState == LoadState.Ready);
|
||||||
|
int notificationCount = !pluggedIn && batteryLevel < PlayerLoader.battery_tolerance ? 1 : 0;
|
||||||
|
AddAssert("check for notification", () => notificationOverlay.UnreadCount.Value == notificationCount);
|
||||||
|
AddStep("click notification", () =>
|
||||||
|
{
|
||||||
|
var scrollContainer = (OsuScrollContainer)notificationOverlay.Children.Last();
|
||||||
|
var flowContainer = scrollContainer.Children.OfType<FillFlowContainer<NotificationSection>>().First();
|
||||||
|
var notification = flowContainer.First();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(notification);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for player load", () => player.IsLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
public void TestEpilepsyWarning(bool warning)
|
public void TestEpilepsyWarning(bool warning)
|
||||||
@ -310,6 +356,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public IReadOnlyList<Mod> DisplayedMods => MetadataInfo.Mods.Value;
|
public IReadOnlyList<Mod> DisplayedMods => MetadataInfo.Mods.Value;
|
||||||
|
|
||||||
|
public new BatteryManager batteryManager => base.batteryManager;
|
||||||
|
|
||||||
public TestPlayerLoader(Func<Player> createPlayer)
|
public TestPlayerLoader(Func<Player> createPlayer)
|
||||||
: base(createPlayer)
|
: base(createPlayer)
|
||||||
{
|
{
|
||||||
|
@ -22,4 +22,4 @@
|
|||||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -16,6 +16,7 @@ namespace osu.Game.Configuration
|
|||||||
{
|
{
|
||||||
SetDefault(Static.LoginOverlayDisplayed, false);
|
SetDefault(Static.LoginOverlayDisplayed, false);
|
||||||
SetDefault(Static.MutedAudioNotificationShownOnce, false);
|
SetDefault(Static.MutedAudioNotificationShownOnce, false);
|
||||||
|
SetDefault(Static.BatteryLowNotificationShownOnce, false);
|
||||||
SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null);
|
SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null);
|
||||||
SetDefault<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
SetDefault<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
||||||
}
|
}
|
||||||
@ -25,6 +26,7 @@ namespace osu.Game.Configuration
|
|||||||
{
|
{
|
||||||
LoginOverlayDisplayed,
|
LoginOverlayDisplayed,
|
||||||
MutedAudioNotificationShownOnce,
|
MutedAudioNotificationShownOnce,
|
||||||
|
BatteryLowNotificationShownOnce,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Info about seasonal backgrounds available fetched from API - see <see cref="APISeasonalBackgrounds"/>.
|
/// Info about seasonal backgrounds available fetched from API - see <see cref="APISeasonalBackgrounds"/>.
|
||||||
|
@ -26,6 +26,7 @@ using osu.Game.Screens.Play.PlayerSettings;
|
|||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
using Xamarin.Essentials;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
@ -121,6 +122,7 @@ namespace osu.Game.Screens.Play
|
|||||||
private void load(SessionStatics sessionStatics)
|
private void load(SessionStatics sessionStatics)
|
||||||
{
|
{
|
||||||
muteWarningShownOnce = sessionStatics.GetBindable<bool>(Static.MutedAudioNotificationShownOnce);
|
muteWarningShownOnce = sessionStatics.GetBindable<bool>(Static.MutedAudioNotificationShownOnce);
|
||||||
|
batteryWarningShownOnce = sessionStatics.GetBindable<bool>(Static.BatteryLowNotificationShownOnce);
|
||||||
|
|
||||||
InternalChild = (content = new LogoTrackingContainer
|
InternalChild = (content = new LogoTrackingContainer
|
||||||
{
|
{
|
||||||
@ -196,6 +198,7 @@ namespace osu.Game.Screens.Play
|
|||||||
Scheduler.Add(new ScheduledDelegate(pushWhenLoaded, Clock.CurrentTime + 1800, 0));
|
Scheduler.Add(new ScheduledDelegate(pushWhenLoaded, Clock.CurrentTime + 1800, 0));
|
||||||
|
|
||||||
showMuteWarningIfNeeded();
|
showMuteWarningIfNeeded();
|
||||||
|
showBatteryWarningIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnResuming(IScreen last)
|
public override void OnResuming(IScreen last)
|
||||||
@ -470,5 +473,73 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Low battery warning
|
||||||
|
private Bindable<bool> batteryWarningShownOnce;
|
||||||
|
|
||||||
|
// Send a warning if battery is less than 20%
|
||||||
|
public const double battery_tolerance = 0.2;
|
||||||
|
|
||||||
|
private void showBatteryWarningIfNeeded()
|
||||||
|
{
|
||||||
|
if (!batteryWarningShownOnce.Value)
|
||||||
|
{
|
||||||
|
// Checks if the notification has not been shown yet, device is unplugged and if device battery is low.
|
||||||
|
if (!batteryManager.PluggedIn && batteryManager.ChargeLevel < battery_tolerance)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Battery level: {0}", batteryManager.ChargeLevel);
|
||||||
|
notificationOverlay?.Post(new BatteryWarningNotification());
|
||||||
|
batteryWarningShownOnce.Value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public BatteryManager batteryManager = new BatteryManager();
|
||||||
|
public class BatteryManager
|
||||||
|
{
|
||||||
|
public double ChargeLevel;
|
||||||
|
public bool PluggedIn;
|
||||||
|
public BatteryManager()
|
||||||
|
{
|
||||||
|
// Attempt to get battery information using Xamarin.Essentials
|
||||||
|
// Xamarin.Essentials throws a NotSupportedOrImplementedException on .NET standard so this only works on iOS/Android
|
||||||
|
// https://github.com/xamarin/Essentials/blob/7218ab88f7fbe00ec3379bd54e6c0ce35ffc0c22/Xamarin.Essentials/Battery/Battery.netstandard.tvos.cs
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ChargeLevel = Battery.ChargeLevel;
|
||||||
|
PluggedIn = Battery.PowerSource == BatteryPowerSource.Battery;
|
||||||
|
}
|
||||||
|
catch (NotImplementedException e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Could not access battery info: {0}", e);
|
||||||
|
ChargeLevel = 1.0;
|
||||||
|
PluggedIn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BatteryWarningNotification : SimpleNotification
|
||||||
|
{
|
||||||
|
public override bool IsImportant => true;
|
||||||
|
|
||||||
|
public BatteryWarningNotification()
|
||||||
|
{
|
||||||
|
Text = "Your battery level is low! Charge your device to prevent interruptions.";
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, NotificationOverlay notificationOverlay)
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.BatteryQuarter;
|
||||||
|
IconBackgound.Colour = colours.RedDark;
|
||||||
|
|
||||||
|
Activated = delegate
|
||||||
|
{
|
||||||
|
notificationOverlay.Hide();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
@ -35,5 +35,6 @@
|
|||||||
<PackageReference Include="SharpCompress" Version="0.28.1" />
|
<PackageReference Include="SharpCompress" Version="0.28.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user