-
-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add device information for MAUI and Android (#1713)
- Loading branch information
1 parent
16111ce
commit a2db32b
Showing
10 changed files
with
268 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
using Sentry.Extensibility; | ||
using Sentry.Protocol; | ||
using Device = Sentry.Protocol.Device; | ||
|
||
namespace Sentry.Maui.Internal; | ||
|
||
internal static class MauiDeviceData | ||
{ | ||
public static void ApplyMauiDeviceData(this Device device, IDiagnosticLogger? logger) | ||
{ | ||
try | ||
{ | ||
// TODO: Add more device data where indicated | ||
|
||
// https://docs.microsoft.com/dotnet/maui/platform-integration/device/information | ||
var deviceInfo = DeviceInfo.Current; | ||
if (deviceInfo.Platform == DevicePlatform.Unknown) | ||
{ | ||
// return early so we don't get NotImplementedExceptions (i.e., in unit tests, etc.) | ||
return; | ||
} | ||
device.Name ??= deviceInfo.Name; | ||
device.Manufacturer ??= deviceInfo.Manufacturer; | ||
device.Model ??= deviceInfo.Model; | ||
device.DeviceType ??= deviceInfo.Idiom.ToString(); | ||
device.Simulator ??= deviceInfo.DeviceType switch | ||
{ | ||
DeviceType.Virtual => true, | ||
DeviceType.Physical => false, | ||
_ => null | ||
}; | ||
// device.Brand ??= ? | ||
// device.Family ??= ? | ||
// device.ModelId ??= ? | ||
// device.Architecture ??= ? | ||
// ? = deviceInfo.Platform; | ||
// ? = deviceInfo.VersionString; | ||
|
||
// https://docs.microsoft.com/dotnet/maui/platform-integration/device/battery | ||
var battery = Battery.Default; | ||
device.BatteryLevel ??= battery.ChargeLevel < 0 ? null : (short)battery.ChargeLevel; | ||
device.BatteryStatus ??= battery.State.ToString(); | ||
device.IsCharging ??= battery.State switch | ||
{ | ||
BatteryState.Unknown => null, | ||
BatteryState.Charging => true, | ||
_ => false | ||
}; | ||
|
||
// https://docs.microsoft.com/dotnet/maui/platform-integration/communication/networking#using-connectivity | ||
var connectivity = Connectivity.Current; | ||
device.IsOnline ??= connectivity.NetworkAccess == NetworkAccess.Internet; | ||
|
||
// https://docs.microsoft.com/dotnet/maui/platform-integration/device/display | ||
var display = DeviceDisplay.Current.MainDisplayInfo; | ||
device.ScreenResolution ??= $"{(int)display.Width}x{(int)display.Height}"; | ||
device.ScreenDensity ??= (float)display.Density; | ||
device.Orientation ??= display.Orientation switch | ||
{ | ||
DisplayOrientation.Portrait => DeviceOrientation.Portrait, | ||
DisplayOrientation.Landscape => DeviceOrientation.Landscape, | ||
_ => null | ||
}; | ||
// device.ScreenDpi ??= ? | ||
// ? = display.RefreshRate; | ||
// ? = display.Rotation; | ||
|
||
// https://docs.microsoft.com/dotnet/maui/platform-integration/device/vibrate | ||
device.SupportsVibration ??= Vibration.Default.IsSupported; | ||
|
||
// https://docs.microsoft.com/dotnet/maui/platform-integration/device/sensors | ||
device.SupportsAccelerometer ??= Accelerometer.IsSupported; | ||
device.SupportsGyroscope ??= Gyroscope.IsSupported; | ||
|
||
// https://docs.microsoft.com/dotnet/maui/platform-integration/device/geolocation | ||
// TODO: How to get without actually trying to make a location request? | ||
// device.SupportsLocationService ??= Geolocation.Default.??? | ||
|
||
// device.SupportsAudio ??= ? | ||
|
||
// device.MemorySize ??= | ||
// device.FreeMemory ??= | ||
// device.UsableMemory ??= | ||
// device.LowMemory ??= | ||
|
||
// device.StorageSize ??= | ||
// device.FreeStorage ??= | ||
// device.ExternalStorageSize ??= | ||
// device.ExternalFreeStorage ??= | ||
|
||
// device.BootTime ??= | ||
// device.DeviceUniqueIdentifier ??= | ||
|
||
//device.CpuDescription ??= ? | ||
//device.ProcessorCount ??= ? | ||
//device.ProcessorFrequency ??= ? | ||
|
||
} | ||
catch (Exception ex) | ||
{ | ||
// Log, but swallow the exception so we can continue sending events | ||
logger?.LogError("Error getting MAUI device information.", ex); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using Sentry.Android.Extensions; | ||
using Sentry.Extensibility; | ||
|
||
namespace Sentry.Android; | ||
|
||
internal class AndroidEventProcessor : ISentryEventProcessor, IDisposable | ||
{ | ||
private readonly Java.IEventProcessor? _androidProcessor; | ||
private readonly Java.Hint _hint = new(); | ||
|
||
public AndroidEventProcessor(SentryAndroidOptions androidOptions) | ||
{ | ||
// Locate the Android SDK's default event processor by its class | ||
// NOTE: This approach avoids hardcoding the class name (which could be obfuscated by proguard) | ||
_androidProcessor = androidOptions.EventProcessors.OfType<JavaObject>() | ||
.Where(o => o.Class == JavaClass.FromType(typeof(DefaultAndroidEventProcessor))) | ||
.Cast<Java.IEventProcessor>() | ||
.FirstOrDefault(); | ||
|
||
// TODO: This would be cleaner, but doesn't compile. Figure out why. | ||
// _androidProcessor = androidOptions.EventProcessors | ||
// .OfType<DefaultAndroidEventProcessor>() | ||
// .FirstOrDefault(); | ||
} | ||
|
||
public SentryEvent Process(SentryEvent @event) | ||
{ | ||
// Get what information we can ourselves first | ||
@event.Contexts.Device.ApplyFromAndroidRuntime(); | ||
|
||
// Copy more information from the Android SDK | ||
if (_androidProcessor is { } androidProcessor) | ||
{ | ||
// TODO: Can we gather more device data directly and remove this? | ||
|
||
// Run a fake event through the Android processor, so we can get context info from the Android SDK. | ||
// We'll want to do this every time, so that all information is current. (ex: device orientation) | ||
using var e = new Java.SentryEvent(); | ||
androidProcessor.Process(e, _hint); | ||
|
||
// Copy what we need to the managed event | ||
if (e.Contexts.Device is { } device) | ||
{ | ||
@event.Contexts.Device.ApplyFromSentryAndroidSdk(device); | ||
} | ||
} | ||
|
||
return @event; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_androidProcessor?.Dispose(); | ||
_hint.Dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using Sentry.Protocol; | ||
|
||
namespace Sentry.Android.Extensions; | ||
|
||
internal static class DeviceExtensions | ||
{ | ||
public static void ApplyFromAndroidRuntime(this Device device) | ||
{ | ||
device.Manufacturer ??= AndroidBuild.Manufacturer; | ||
device.Brand ??= AndroidBuild.Brand; | ||
device.Model ??= AndroidBuild.Model; | ||
|
||
if (AndroidBuild.SupportedAbis is { } abis) | ||
{ | ||
device.Architecture ??= abis[0]; | ||
} | ||
else | ||
{ | ||
#pragma warning disable CS0618 // Type or member is obsolete | ||
device.Architecture ??= AndroidBuild.CpuAbi; | ||
#pragma warning restore CS0618 // Type or member is obsolete | ||
} | ||
} | ||
|
||
public static void ApplyFromSentryAndroidSdk(this Device device, Java.Protocol.Device d) | ||
{ | ||
// We already have these above | ||
// device.Manufacturer ??= d.Manufacturer; | ||
// device.Brand ??= d.Brand; | ||
// device.Model ??= d.Model; | ||
// device.Architecture ??= d.GetArchs()?.FirstOrDefault(); | ||
|
||
device.Name ??= d.Name; | ||
device.Family ??= d.Family; | ||
device.ModelId ??= d.ModelId; | ||
device.BatteryLevel ??= d.BatteryLevel?.ShortValue(); | ||
device.IsCharging ??= d.IsCharging()?.BooleanValue(); | ||
device.IsOnline ??= d.IsOnline()?.BooleanValue(); | ||
device.Orientation ??= d.Orientation?.ToDeviceOrientation(); | ||
device.Simulator ??= d.IsSimulator()?.BooleanValue(); | ||
device.MemorySize ??= d.MemorySize?.LongValue(); | ||
device.FreeMemory ??= d.FreeMemory?.LongValue(); | ||
device.UsableMemory ??= d.UsableMemory?.LongValue(); | ||
device.LowMemory ??= d.IsLowMemory()?.BooleanValue(); | ||
device.StorageSize ??= d.StorageSize?.LongValue(); | ||
device.FreeStorage ??= d.FreeStorage?.LongValue(); | ||
device.ExternalStorageSize ??= d.ExternalStorageSize?.LongValue(); | ||
device.ExternalFreeStorage ??= d.ExternalFreeStorage?.LongValue(); | ||
device.ScreenResolution ??= $"{d.ScreenWidthPixels}x{d.ScreenHeightPixels}"; | ||
device.ScreenDensity ??= d.ScreenDensity?.FloatValue(); | ||
device.ScreenDpi ??= d.ScreenDpi?.IntValue(); | ||
device.BootTime ??= d.BootTime?.ToDateTimeOffset(); | ||
device.DeviceUniqueIdentifier ??= d.Id; | ||
|
||
// TODO: Can we get these from somewhere? | ||
//device.ProcessorCount ??= ? | ||
//device.CpuDescription ??= ? | ||
//device.ProcessorFrequency ??= ? | ||
//device.DeviceType ??= ? | ||
//device.BatteryStatus ??= ? | ||
//device.SupportsVibration ??= ? | ||
//device.SupportsAccelerometer ??= ? | ||
//device.SupportsGyroscope ??= ? | ||
//device.SupportsAudio ??= ? | ||
//device.SupportsLocationService ??= ? | ||
|
||
} | ||
|
||
public static DeviceOrientation ToDeviceOrientation(this Java.Protocol.Device.DeviceOrientation orientation) => | ||
orientation.Name() switch | ||
{ | ||
"PORTRAIT" => DeviceOrientation.Portrait, | ||
"LANDSCAPE" => DeviceOrientation.Landscape, | ||
_ => throw new ArgumentOutOfRangeException(nameof(orientation), orientation.Name(), message: default) | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters