BatteryService
Cross-platform service for monitoring device battery information and power state.
Namespace: GamaLearn.Services
Assembly: GamaLearn.Maui.Core
Overview
BatteryService provides a clean, testable wrapper around .NET MAUI's battery APIs. It monitors battery charge level, charging state, power source, and energy saver mode with automatic event notifications.
Installation
dotnet add package GamaLearn.Maui.Core
Setup
Registration
Register the service in your MauiProgram.cs:
using GamaLearn;
using GamaLearn.Services;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>();
// Register Battery Service
builder.Services.AddBatteryService();
// Or register all core services at once
builder.Services.AddGamaLearnCoreServices();
return builder.Build();
}
}
Properties
ChargeLevel
Type: double (read-only)
Gets the current battery charge level as a percentage (0.0 to 1.0).
double charge = batteryService.ChargeLevel; // 0.75 = 75%
State
Type: BatteryState (read-only)
Gets the current battery state.
Possible Values:
BatteryState.Charging- Battery is chargingBatteryState.Discharging- Battery is discharging (on battery power)BatteryState.Full- Battery is fully chargedBatteryState.NotCharging- Not charging but plugged inBatteryState.Unknown- State cannot be determined
if (batteryService.State == BatteryState.Charging)
{
// Device is charging
}
PowerSource
Type: BatteryPowerSource (read-only)
Gets the power source being used.
Possible Values:
BatteryPowerSource.Battery- Running on batteryBatteryPowerSource.AC- Plugged into AC powerBatteryPowerSource.Usb- Plugged into USBBatteryPowerSource.Wireless- Wireless chargingBatteryPowerSource.Unknown- Unknown power source
if (batteryService.PowerSource == BatteryPowerSource.Battery)
{
// Running on battery, consider power-saving measures
}
EnergySaverStatus
Type: bool (read-only)
Gets whether the device is in energy saver (low-power) mode.
if (batteryService.EnergySaverStatus)
{
// Reduce background operations
}
Methods
StartMonitoring()
Starts monitoring battery changes. Call this to begin receiving battery change events.
batteryService.StartMonitoring();
StopMonitoring()
Stops monitoring battery changes. Call this when you no longer need updates to save resources.
batteryService.StopMonitoring();
Events
BatteryInfoChanged
Occurs when the battery charge level, state, or power source changes.
Event Args: BatteryInfoChangedEventArgs
ChargeLevel- New charge level (0.0 to 1.0)State- New battery statePowerSource- New power source
batteryService.BatteryInfoChanged += (sender, e) =>
{
Debug.WriteLine($"Battery: {e.ChargeLevel:P0}, State: {e.State}, Power: {e.PowerSource}");
};
EnergySaverStatusChanged
Occurs when energy saver mode is toggled.
Event Args: EnergySaverStatusChangedEventArgs
IsEnergySaverOn- Whether energy saver is now enabled
batteryService.EnergySaverStatusChanged += (sender, e) =>
{
if (e.IsEnergySaverOn)
{
// Reduce animations, background tasks, etc.
}
};
Usage Examples
Basic Usage
public class MainViewModel
{
private readonly IBatteryService batteryService;
public MainViewModel(IBatteryService batteryService)
{
this.batteryService = batteryService;
// Start monitoring
batteryService.StartMonitoring();
// Subscribe to events
batteryService.BatteryInfoChanged += OnBatteryInfoChanged;
batteryService.EnergySaverStatusChanged += OnEnergySaverStatusChanged;
}
private void OnBatteryInfoChanged(object? sender, BatteryInfoChangedEventArgs e)
{
Debug.WriteLine($"Battery level: {e.ChargeLevel:P0}");
if (e.ChargeLevel < 0.2)
{
ShowLowBatteryWarning();
}
}
private void OnEnergySaverStatusChanged(object? sender, EnergySaverStatusChangedEventArgs e)
{
if (e.IsEnergySaverOn)
{
ReduceBackgroundActivity();
}
}
}
Battery Indicator
public class BatteryIndicatorViewModel : ObservableObject
{
private readonly IBatteryService batteryService;
[ObservableProperty]
private double chargeLevel;
[ObservableProperty]
private string batteryIcon = "battery_full";
[ObservableProperty]
private Color batteryColor = Colors.Green;
public BatteryIndicatorViewModel(IBatteryService batteryService)
{
this.batteryService = batteryService;
batteryService.StartMonitoring();
batteryService.BatteryInfoChanged += OnBatteryInfoChanged;
UpdateBatteryUI();
}
private void OnBatteryInfoChanged(object? sender, BatteryInfoChangedEventArgs e)
{
ChargeLevel = e.ChargeLevel;
UpdateBatteryUI();
}
private void UpdateBatteryUI()
{
BatteryIcon = ChargeLevel switch
{
>= 0.9 => "battery_full",
>= 0.6 => "battery_6_bar",
>= 0.4 => "battery_4_bar",
>= 0.2 => "battery_2_bar",
_ => "battery_alert"
};
BatteryColor = ChargeLevel switch
{
>= 0.3 => Colors.Green,
>= 0.2 => Colors.Orange,
_ => Colors.Red
};
}
}
Power-Aware Operations
public class SyncService
{
private readonly IBatteryService batteryService;
private readonly ILogger<SyncService> logger;
public SyncService(IBatteryService batteryService, ILogger<SyncService> logger)
{
this.batteryService = batteryService;
this.logger = logger;
}
public async Task<bool> SyncDataAsync()
{
// Check battery conditions before syncing
if (!ShouldSync())
{
logger.LogInformation("Skipping sync due to battery conditions");
return false;
}
logger.LogInformation("Starting data sync");
await PerformSyncAsync();
return true;
}
private bool ShouldSync()
{
// Don't sync if battery is very low
if (batteryService.ChargeLevel < 0.15)
{
logger.LogInformation("Battery too low for sync: {ChargeLevel:P0}",
batteryService.ChargeLevel);
return false;
}
// Don't sync if in energy saver mode (unless charging)
if (batteryService.EnergySaverStatus &&
batteryService.State != BatteryState.Charging)
{
logger.LogInformation("Energy saver mode enabled, skipping sync");
return false;
}
// Prefer to sync when plugged in
if (batteryService.PowerSource != BatteryPowerSource.Battery)
{
logger.LogInformation("Device is plugged in, safe to sync");
return true;
}
// Only sync on battery if charge is adequate
return batteryService.ChargeLevel >= 0.5;
}
private async Task PerformSyncAsync()
{
// Your sync logic here
await Task.Delay(1000);
}
}
Download Manager
public class DownloadManager
{
private readonly IBatteryService batteryService;
private bool isDownloading;
public DownloadManager(IBatteryService batteryService)
{
this.batteryService = batteryService;
batteryService.StartMonitoring();
batteryService.BatteryInfoChanged += OnBatteryInfoChanged;
}
public async Task StartDownloadAsync(string url)
{
if (!CanDownload())
{
throw new InvalidOperationException("Cannot download: battery conditions not met");
}
isDownloading = true;
await PerformDownloadAsync(url);
isDownloading = false;
}
private void OnBatteryInfoChanged(object? sender, BatteryInfoChangedEventArgs e)
{
// Pause downloads if battery gets too low
if (isDownloading && e.ChargeLevel < 0.1)
{
PauseDownload();
}
}
private bool CanDownload()
{
// Large downloads only when charging or battery > 30%
return batteryService.State == BatteryState.Charging ||
batteryService.ChargeLevel > 0.3;
}
private async Task PerformDownloadAsync(string url)
{
// Download logic
await Task.Delay(1000);
}
private void PauseDownload()
{
// Pause logic
}
}
Settings Page
public class SettingsViewModel : ObservableObject
{
private readonly IBatteryService batteryService;
public string BatteryInfo => $"{batteryService.ChargeLevel:P0} - {batteryService.State}";
public string PowerSource => batteryService.PowerSource.ToString();
public bool IsEnergySaverOn => batteryService.EnergySaverStatus;
public SettingsViewModel(IBatteryService batteryService)
{
this.batteryService = batteryService;
batteryService.StartMonitoring();
batteryService.BatteryInfoChanged += (s, e) =>
{
OnPropertyChanged(nameof(BatteryInfo));
OnPropertyChanged(nameof(PowerSource));
};
batteryService.EnergySaverStatusChanged += (s, e) =>
{
OnPropertyChanged(nameof(IsEnergySaverOn));
};
}
}
<VerticalStackLayout Padding="16">
<Label Text="Device Status" FontSize="20" FontAttributes="Bold" />
<Label Text="Battery Level:" />
<Label Text="{Binding BatteryInfo}" FontAttributes="Bold" />
<Label Text="Power Source:" />
<Label Text="{Binding PowerSource}" FontAttributes="Bold" />
<Label Text="Energy Saver:" />
<Label Text="{Binding IsEnergySaverOn}" FontAttributes="Bold" />
</VerticalStackLayout>
Background Task Scheduler
public class BackgroundTaskScheduler
{
private readonly IBatteryService batteryService;
private Timer? scheduledTask;
public BackgroundTaskScheduler(IBatteryService batteryService)
{
this.batteryService = batteryService;
batteryService.StartMonitoring();
}
public void ScheduleTask(Func<Task> task, TimeSpan interval)
{
scheduledTask?.Dispose();
scheduledTask = new Timer(async _ =>
{
if (ShouldRunTask())
{
await task();
}
}, null, interval, interval);
}
private bool ShouldRunTask()
{
// Don't run background tasks in low battery or energy saver mode
if (batteryService.ChargeLevel < 0.2 || batteryService.EnergySaverStatus)
{
return false;
}
return true;
}
public void Dispose()
{
scheduledTask?.Dispose();
batteryService.StopMonitoring();
}
}
Best Practices
1. Always Stop Monitoring
✅ Good:
public class MyViewModel : IDisposable
{
public MyViewModel(IBatteryService batteryService)
{
this.batteryService = batteryService;
batteryService.StartMonitoring();
}
public void Dispose()
{
batteryService.StopMonitoring();
}
}
❌ Avoid:
// Starting monitoring without ever stopping (memory leak)
batteryService.StartMonitoring();
2. Respect Energy Saver Mode
✅ Good:
if (batteryService.EnergySaverStatus)
{
// Reduce animations, polling, background tasks
DisableNonEssentialFeatures();
}
❌ Avoid:
// Ignoring energy saver mode and draining battery
PerformExpensiveOperations();
3. Use Dependency Injection
✅ Good:
public class MyService
{
private readonly IBatteryService batteryService;
public MyService(IBatteryService batteryService)
{
this.batteryService = batteryService;
}
}
❌ Avoid:
// Direct instantiation, not testable
var batteryService = new BatteryService();
Platform Notes
Android
- Requires
BatteryStatspermission (automatically included) - Battery state updates immediately
- Energy saver mode reflects system power saving settings
iOS
- Battery monitoring is enabled automatically
- Low power mode is reflected in
EnergySaverStatus - Battery level updates every 1% change
Windows
- Desktop Windows may always report
ChargeLevel = 1.0on devices without batteries - Laptops report accurate battery information
MacCatalyst
- Similar to iOS behavior
- Battery information available on MacBooks
Troubleshooting
Battery Level Always 1.0
This is expected on desktop devices without batteries (Windows desktops, some development machines).
Events Not Firing
Make sure you called StartMonitoring():
batteryService.StartMonitoring();
batteryService.BatteryInfoChanged += OnBatteryInfoChanged;
Memory Leaks
Always call StopMonitoring() or implement IDisposable:
public void Dispose()
{
batteryService.BatteryInfoChanged -= OnBatteryInfoChanged;
batteryService.StopMonitoring();
}
See Also
- DeviceInfoService - Device information
- AppRatingService - In-app ratings
- Guard - Argument validation