feat(feedback): Add screenshot attachment button to user feedback widget - #5828
feat(feedback): Add screenshot attachment button to user feedback widget#5828markushi wants to merge 13 commits into
Conversation
|
📲 Install BuildsAndroid
|
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d8b6ce1 | 314.62 ms | 348.67 ms | 34.05 ms |
| 0d66c0b | 327.83 ms | 403.40 ms | 75.57 ms |
| fcec2f2 | 311.35 ms | 384.94 ms | 73.59 ms |
| c3ee041 | 310.64 ms | 361.90 ms | 51.26 ms |
| 22f4345 | 313.52 ms | 364.96 ms | 51.44 ms |
| 6b019b7 | 343.31 ms | 417.23 ms | 73.91 ms |
| b6cfb57 | 372.92 ms | 507.77 ms | 134.85 ms |
| b67bb28 | 307.59 ms | 341.24 ms | 33.65 ms |
| 5865051 | 319.74 ms | 365.60 ms | 45.86 ms |
| 80fd6ad | 321.06 ms | 375.79 ms | 54.73 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d8b6ce1 | 0 B | 0 B | 0 B |
| 0d66c0b | 1.58 MiB | 2.29 MiB | 720.89 KiB |
| fcec2f2 | 1.58 MiB | 2.12 MiB | 551.51 KiB |
| c3ee041 | 0 B | 0 B | 0 B |
| 22f4345 | 1.58 MiB | 2.29 MiB | 719.83 KiB |
| 6b019b7 | 0 B | 0 B | 0 B |
| b6cfb57 | 1.58 MiB | 2.28 MiB | 718.80 KiB |
| b67bb28 | 0 B | 0 B | 0 B |
| 5865051 | 0 B | 0 B | 0 B |
| 80fd6ad | 0 B | 0 B | 0 B |
Previous results on branch: feat/feedback-screenshot-attachment
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 71243e7 | 313.69 ms | 370.22 ms | 56.54 ms |
| 37c6869 | 327.68 ms | 381.06 ms | 53.38 ms |
| 676848b | 367.87 ms | 443.02 ms | 75.15 ms |
| 86e5409 | 326.20 ms | 351.31 ms | 25.11 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 71243e7 | 0 B | 0 B | 0 B |
| 37c6869 | 0 B | 0 B | 0 B |
| 676848b | 0 B | 0 B | 0 B |
| 86e5409 | 0 B | 0 B | 0 B |
…entry/sentry-java into feat/feedback-screenshot-attachment
runningcode
left a comment
There was a problem hiding this comment.
Thanks for adding this!
| mime, | ||
| "event.attachment", | ||
| false)); | ||
| } catch (Throwable t) { |
There was a problem hiding this comment.
I decided I'm always going to comment whenever we add new usages of this. Sorry to bring it up again.
- How will we know that this feature is working in production if we swallow all errors?
- Since we're dealing with images, files and attachments how we we know we aren't swallowing a permissions issue or OOM?
There was a problem hiding this comment.
Switched to using the newly added ExceptionUtils.rethrowIfFatal, so OOM and linkage errors propagate. getUriSize now logs the throwable too, it was silent before.
| return cursor.getLong(sizeIndex); | ||
| } | ||
| } | ||
| } catch (Throwable ignored) { |
There was a problem hiding this comment.
same comment here as above.
There was a problem hiding this comment.
Switched to using the newly added ExceptionUtils.rethrowIfFatal, so OOM and linkage errors propagate. getUriSize now logs the throwable too, it was silent before.
Use term "screenshot" everywhere Improve nullability handling
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0a3d51d. Configure here.
…hment paths Routes the three catch-all blocks around the screenshot picker through ExceptionUtils.rethrowIfFatal, so OOM, ThreadDeath and linkage errors propagate instead of being hidden, and logs the previously silent failure in getUriSize. Also moves the androidx.activity availability check out of SentryFeedbackScreenshotPicker, so the class is only loaded once the check passed, as its javadoc requires. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| ((ComponentActivity) activity) | ||
| .getActivityResultRegistry() | ||
| .register( | ||
| "sentry_user_feedback_screenshot_picker", | ||
| new ActivityResultContracts.PickVisualMedia(), | ||
| (@Nullable Uri uri) -> { | ||
| if (uri != null) { | ||
| callback.onScreenshotPicked(uri); | ||
| } | ||
| }); | ||
| return new SentryFeedbackScreenshotPicker(launcher); |
There was a problem hiding this comment.
Bug: The ActivityResultRegistry.register() call for the screenshot picker is made after the Activity's lifecycle is STARTED, which will throw an unhandled IllegalStateException and crash the app.
Severity: CRITICAL
Suggested Fix
The registration of the ActivityResultLauncher should be moved to a point in the lifecycle before the host Activity is started, such as in the onCreate() method of the Activity or Fragment. If registration must happen dynamically, wrap the call in a try-catch block to handle the IllegalStateException gracefully, although this would prevent the feature from working. The recommended approach is to register early in the lifecycle.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
sentry-android-core/src/main/java/io/sentry/android/core/SentryFeedbackScreenshotPicker.java#L37-L48
Potential issue: The `SentryUserFeedbackForm` dialog attempts to register an
`ActivityResultLauncher` for the screenshot picker within its `onStart()` method. This
registration is performed on the host `ComponentActivity`, which is already in the
`STARTED` or `RESUMED` state. According to Android's `ActivityResultRegistry`
documentation, `register()` must be called before the `LifecycleOwner` reaches the
`STARTED` state. Calling it after this point throws an `IllegalStateException`. Since
the call to `SentryFeedbackScreenshotPicker.register()` is not wrapped in a `try-catch`
block, this exception is unhandled and will crash the application when the feedback form
is displayed.
Also affects:
sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java:385~385

📜 Description
Adds an "Add a screenshot" button to the Android user feedback form that opens the
androidx photo picker (
ActivityResultContracts.PickVisualMedia, images only) and sendsthe picked image as an attachment in the same envelope as the feedback.
Screen_recording_20260723_183244.mp4
SentryFeedbackOptions:enableScreenshot(defaulttrue, matching the JS SDK),addScreenshotButtonLabel,removeScreenshotButtonLabel, plus theio.sentry.feedback.enable-screenshotmanifest flagandroidx.activity:activity:1.8.2is added as compileOnly — no new transitivedependency; the button is hidden (with a warning log) when androidx.activity is missing
or the host Activity is not a
ComponentActivitymaxAttachmentSizeat pick time💡 Motivation and Context
💚 How did you test it?
Unit tests + Manual testing.
📝 Checklist
sendDefaultPIIis enabled.