Skip to content

Commit 3460c28

Browse files
Added the ability to Mask/Unmask controls by Type
1 parent ba18078 commit 3460c28

File tree

7 files changed

+68
-11
lines changed

7 files changed

+68
-11
lines changed

samples/Sentry.Samples.Maui/MainPage.xaml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
<Image
1414
Source="dotnet_bot.png"
15+
sentry:SessionReplay.Mask="Unmask"
1516
SemanticProperties.Description="Cute dot net bot waving hi to you!"
1617
HeightRequest="200"
1718
HorizontalOptions="Center" />
@@ -32,55 +33,48 @@
3233
<Button
3334
x:Name="CounterBtn"
3435
Text="Click me"
35-
sentry:SessionReplay.Mask="Unmask"
3636
SemanticProperties.Hint="Counts the number of times you click."
3737
Clicked="OnCounterClicked"
3838
HorizontalOptions="Center" />
3939

4040
<Button
4141
x:Name="ThrowAndCaptureBtn"
4242
Text="Throw and Capture Exception"
43-
sentry:SessionReplay.Mask="Unmask"
4443
SemanticProperties.Hint="Throws an exception and captures it."
4544
Clicked="OnCapturedExceptionClicked"
4645
HorizontalOptions="Center" />
4746

4847
<Button
4948
x:Name="ThrowUnhandledBtn"
5049
Text="Throw Unhandled .NET Exception (Crash)"
51-
sentry:SessionReplay.Mask="Unmask"
5250
SemanticProperties.Hint="Throws an unhandled .NET exception, crashing the app."
5351
Clicked="OnUnhandledExceptionClicked"
5452
HorizontalOptions="Center" />
5553

5654
<Button
5755
x:Name="ThrowBackgroundUnhandledBtn"
5856
Text="Throw Unhandled .NET Exception on Background Thread (Crash)"
59-
sentry:SessionReplay.Mask="Unmask"
6057
SemanticProperties.Hint="Throws an unhandled .NET exception on a background thread, crashing the app."
6158
Clicked="OnBackgroundThreadUnhandledExceptionClicked"
6259
HorizontalOptions="Center" />
6360

6461
<Button
6562
x:Name="JavaCrashBtn"
6663
Text="Throw Java Exception (Crash)"
67-
sentry:SessionReplay.Mask="Unmask"
6864
SemanticProperties.Hint="Throws an unhandled Java exception, crashing the app."
6965
Clicked="OnJavaCrashClicked"
7066
HorizontalOptions="Center" />
7167

7268
<Button
7369
x:Name="NativeCrashBtn"
7470
Text="Cause Native Crash"
75-
sentry:SessionReplay.Mask="Unmask"
7671
SemanticProperties.Hint="Performs an invalid native operation, crashing the app."
7772
Clicked="OnNativeCrashClicked"
7873
HorizontalOptions="Center" />
7974

8075
<Button
8176
x:Name="FeedbackBtn"
8277
Text="Submit Feedback"
83-
sentry:SessionReplay.Mask="Unmask"
8478
SemanticProperties.Hint="Provides a form that can be used to capture open feedback from the user."
8579
Clicked="OnFeedbackClicked"
8680
HorizontalOptions="Center" />

samples/Sentry.Samples.Maui/MauiProgram.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,17 @@ public static MauiApp CreateMauiApp()
2525
options.Debug = true;
2626
options.SampleRate = 1.0F;
2727

28-
#if ANDROID
28+
#if __ANDROID__
2929
// Currently experimental support is only available on Android
3030
options.Native.ExperimentalOptions.SessionReplay.OnErrorSampleRate = 1.0;
3131
options.Native.ExperimentalOptions.SessionReplay.SessionSampleRate = 1.0;
32-
// Mask all images and text by default.
33-
// This can be overridden for individual view elements (see MainPage.xaml for an example)
32+
// Mask all images and text by default. This can be overridden for individual view elements via the
33+
// sentry:SessionReplay.Mask XML attribute (see MainPage.xaml for an example)
3434
options.Native.ExperimentalOptions.SessionReplay.MaskAllImages = true;
3535
options.Native.ExperimentalOptions.SessionReplay.MaskAllText = true;
36+
// Alternatively the masking behaviour for entire classes of VisualElements can be configured here as
37+
// an exception to the default behaviour.
38+
options.Native.ExperimentalOptions.SessionReplay.UnmaskControlsOfType<Button>();
3639
#endif
3740

3841
options.SetBeforeScreenshotCapture((@event, hint) =>

samples/Sentry.Samples.Maui/Platforms/Android/MainActivity.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
#if __ANDROID__
12
using Android.App;
23
using Android.Content.PM;
4+
using Android.OS;
5+
#endif
36

47
namespace Sentry.Samples.Maui;
58

src/Sentry.Maui/Internal/MauiEventsBinder.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
using Microsoft.Extensions.Options;
2+
using Microsoft.Maui.Platform;
3+
using Sentry.Extensibility;
4+
#if __ANDROID__
5+
using View = Android.Views.View;
6+
#endif
27

38
namespace Sentry.Maui.Internal;
49

@@ -245,11 +250,13 @@ internal void HandleVisualElementEvents(VisualElement element, bool bind = true)
245250
{
246251
element.Focused += OnElementOnFocused;
247252
element.Unfocused += OnElementOnUnfocused;
253+
element.Loaded += OnElementLoaded;
248254
}
249255
else
250256
{
251257
element.Focused -= OnElementOnFocused;
252258
element.Unfocused -= OnElementOnUnfocused;
259+
element.Loaded -= OnElementLoaded;
253260
}
254261
}
255262

@@ -409,6 +416,40 @@ private void OnElementOnFocused(object? sender, FocusEventArgs _) =>
409416
private void OnElementOnUnfocused(object? sender, FocusEventArgs _) =>
410417
_hub.AddBreadcrumbForEvent(_options, sender, nameof(VisualElement.Unfocused), SystemType, RenderingCategory);
411418

419+
private void OnElementLoaded(object? sender, EventArgs _)
420+
{
421+
if (sender is not VisualElement element)
422+
{
423+
_options.LogDebug("OnElementLoaded: sender is not a VisualElement");
424+
return;
425+
}
426+
427+
var handler = element.Handler;
428+
if (handler is null)
429+
{
430+
_options.LogDebug("OnElementLoaded: element.Handler is null");
431+
return;
432+
}
433+
434+
#if __ANDROID__
435+
if (element.Handler?.PlatformView is not View nativeView)
436+
{
437+
return;
438+
}
439+
440+
if (_options.Native.ExperimentalOptions.SessionReplay.MaskedControls.Contains(sender.GetType()))
441+
{
442+
nativeView.Tag = "sentry-mask";
443+
_options.LogDebug("OnElementLoaded: Successfully set sentry-mask tag on native view");
444+
}
445+
else if (_options.Native.ExperimentalOptions.SessionReplay.UnmaskedControls.Contains(element.GetType()))
446+
{
447+
nativeView.Tag = "sentry-unmask";
448+
_options.LogDebug("OnElementLoaded: Successfully set sentry-unmask tag on native view");
449+
}
450+
#endif
451+
}
452+
412453
// Shell Events
413454

414455
private void OnShellOnNavigating(object? sender, ShellNavigatingEventArgs e) =>

src/Sentry.Maui/SentryMauiOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public SentryMauiOptions()
8181
/// if this callback return false the capture will not take place
8282
/// </remarks>
8383
/// <code>
84-
///
84+
///
8585
///options.SetBeforeCapture((@event, hint) =>
8686
///{
8787
/// // Return true to capture or false to prevent the capture

src/Sentry.Maui/SessionReplay.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#if __ANDROID__
22
using View = Android.Views.View;
3+
using Android.Views;
4+
using Java.Lang;
5+
using Microsoft.Maui.Handlers;
6+
using Microsoft.Maui.Platform;
37
#endif
48

59
namespace Sentry.Maui;

src/Sentry/Platforms/Android/NativeOptions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,18 @@ public class NativeSentryReplayOptions
272272
public double? SessionSampleRate { get; set; }
273273
public bool MaskAllImages { get; set; } = true;
274274
public bool MaskAllText { get; set; } = true;
275+
internal HashSet<Type> MaskedControls { get; } = [];
276+
internal HashSet<Type> UnmaskedControls { get; } = [];
277+
278+
public void MaskControlsOfType<T>()
279+
{
280+
MaskedControls.Add(typeof(T));
281+
}
282+
283+
public void UnmaskControlsOfType<T>()
284+
{
285+
UnmaskedControls.Add(typeof(T));
286+
}
275287
}
276288

277289
/// <summary>

0 commit comments

Comments
 (0)