Skip to content

feat(feedback): Support runtime enable/disable of shake-to-report - #5827

Merged
markushi merged 16 commits into
mainfrom
feat/runtime-enable-disable-shake-to-report
Aug 13, 2026
Merged

feat(feedback): Support runtime enable/disable of shake-to-report#5827
markushi merged 16 commits into
mainfrom
feat/runtime-enable-disable-shake-to-report

Conversation

@markushi

@markushi markushi commented Jul 23, 2026

Copy link
Copy Markdown
Member

📜 Description

Adds a runtime API to toggle shake-to-report after Sentry.init():

  • Sentry.feedback().enableOnShake()
  • Sentry.feedback().disableOnShake()
  • Sentry.feedback().isOnShakeEnabled()

SentryFeedbackOptions.isUseShakeGesture() now only determines the initial state; the runtime API overrides it afterwards. Propagation works similar to IFormHandler / ReplayController by introducing a new SentryFeedbackOptions.IShakeController, implemented by FeedbackShakeIntegration on Android and by a logging no-op elsewhere.

This also required re-wiring on-demand dialogs vs. the automatic ones, so that no duplicate dialogs are shown and no duplicate detectors run at the same time:

  • FeedbackShakeIntegration is always installed and registers itself as the IShakeController, even when the option starts out disabled — otherwise there would be nothing to enable later. It arms/disarms the detector in enableOnShake() / disableOnShake().
  • Any visible form reports itself and its host activity to the integration (onFormVisible in onStart, onFormGone in onStop, with onDetachedFromWindow as a safety net for teardown without a dismiss). Detection is suppressed for the activity hosting a form and only re-armed once no form remains there, so neither a form on a backgrounded activity nor one of two simultaneously visible forms can re-enable detection under a visible one. This replaces the previous onFormClose swap-and-restore dance, which was fragile and could leak the host activity.
  • SentryUserFeedbackForm only starts a detector of its own for the per-form opt-in case (useShakeGesture enabled via a configurator while it is globally off); otherwise it defers to the integration, including if shake-to-report gets enabled globally between form creation and the shake.
  • User-supplied onFormOpen / onFormClose / onSubmitSuccess / onSubmitError callbacks are now guarded, so a crashing callback can't take down the app or skip SDK-side cleanup.

💡 Motivation and Context

Having a runtime option to enable / disable the feedback.
Closes #5486 (#5486)

💚 How did you test it?

Unit tests (FeedbackShakeIntegrationTest, SentryUserFeedbackFormTest, FeedbackApiTest, SentryOptionsTest) + manual testing with the Android sample app.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

  • Docs update for the new runtime API (docs repo)

@markushi
markushi marked this pull request as ready for review July 23, 2026 16:14
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 239881d

@sentry

sentry Bot commented Jul 23, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.53.0 (1) release

⚙️ sentry-android Build Distribution Settings

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 315.24 ms 380.73 ms 65.48 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
6b019b7 343.31 ms 417.23 ms 73.91 ms
d15471f 286.65 ms 314.68 ms 28.03 ms
d217708 409.83 ms 474.72 ms 64.89 ms
d500866 326.13 ms 378.70 ms 52.58 ms
fcec2f2 314.96 ms 373.66 ms 58.70 ms
d501a7e 314.55 ms 343.34 ms 28.79 ms
7414e9b 322.49 ms 378.88 ms 56.39 ms
fcec2f2 357.47 ms 447.32 ms 89.85 ms
a416a65 316.52 ms 359.67 ms 43.15 ms
983e0f0 350.64 ms 386.44 ms 35.79 ms

App size

Revision Plain With Sentry Diff
6b019b7 0 B 0 B 0 B
d15471f 1.58 MiB 2.13 MiB 559.54 KiB
d217708 1.58 MiB 2.10 MiB 532.97 KiB
d500866 0 B 0 B 0 B
fcec2f2 1.58 MiB 2.12 MiB 551.50 KiB
d501a7e 0 B 0 B 0 B
7414e9b 0 B 0 B 0 B
fcec2f2 1.58 MiB 2.12 MiB 551.50 KiB
a416a65 1.58 MiB 2.12 MiB 555.26 KiB
983e0f0 0 B 0 B 0 B

Previous results on branch: feat/runtime-enable-disable-shake-to-report

Startup times

Revision Plain With Sentry Diff
ad80f17 315.06 ms 364.31 ms 49.24 ms
7578b08 320.47 ms 375.35 ms 54.88 ms
10e52bd 358.70 ms 433.06 ms 74.36 ms
0400a6b 448.14 ms 494.02 ms 45.88 ms
be39d9f 343.92 ms 417.98 ms 74.06 ms
8594d29 355.30 ms 449.74 ms 94.44 ms
d65301f 330.76 ms 381.63 ms 50.88 ms
3a16473 370.90 ms 449.96 ms 79.06 ms

App size

Revision Plain With Sentry Diff
ad80f17 0 B 0 B 0 B
7578b08 0 B 0 B 0 B
10e52bd 0 B 0 B 0 B
0400a6b 0 B 0 B 0 B
be39d9f 0 B 0 B 0 B
8594d29 0 B 0 B 0 B
d65301f 0 B 0 B 0 B
3a16473 0 B 0 B 0 B

markushi added 2 commits July 23, 2026 22:03
…r.setDialog to prevent overlapping feedback dialogs
…e-to-report' into feat/runtime-enable-disable-shake-to-report
…strong dialog reference cannot leak its activity
@markushi
markushi marked this pull request as draft July 24, 2026 06:09
@markushi
markushi marked this pull request as ready for review July 24, 2026 06:37
@linear-code

linear-code Bot commented Jul 24, 2026

Copy link
Copy Markdown

JAVA-539

Comment thread sentry/src/main/java/io/sentry/IFeedbackApi.java

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just some small things!

Comment thread sentry/src/main/java/io/sentry/IFeedbackApi.java Outdated
- Scope shake suppression to the activity a feedback form is showing on, instead
  of a global paused flag. A dialog lives in its activity's window and is never
  notified when that activity is backgrounded, so tracking the owning activity
  removes the lifecycle heuristics entirely
- Re-check enabled on shake dispatch so a concurrent disableOnShake() cannot
  still show a form
- Narrow user-callback guards from Throwable to Exception so Errors propagate
- Rename isFeedbackOnShakeEnabled() to isOnShakeEnabled() for consistency with
  enableOnShake()/disableOnShake(), and drop @ApiStatus.Internal

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
markushi and others added 4 commits August 12, 2026 13:42
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Shake suppression while a form is visible was keyed on a single activity
ref resolved from CurrentActivityHolder, which is not necessarily the
activity the form is showing on, and any form teardown cleared it. With
two forms visible at once - e.g. showForm() called while a form is
already up - the first one going away re-armed detection under the
second, so a shake could stack another form on top.

Forms now report themselves and their host activity to
FeedbackShakeIntegration, which tracks them individually and only
re-arms detection once no form remains on the current activity. Since
the host activity is Android-only, pausing moves off the cross-platform
IShakeController onto the integration itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
On Android these are dialogs, so name the internal members after what
they are. The public API keeps "form" (SentryUserFeedbackForm,
onFormOpen/onFormClose, showForm) since renaming it would be breaking
and it is not Android-specific.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dialog.show() runs onStart() - which reports the dialog as visible and
stops shake detection - before adding the window, so a failure in
addView() left the dialog registered as visible with no callback ever
reporting it gone. Shake detection then stayed off for the rest of the
activity's lifetime while isOnShakeEnabled() still reported true.

Also drop the global useShakeGesture check from the dialog's own shake
opt-in: whether the integration is currently detecting is the only
thing that matters there, and a dialog configured for shake detection
should get it once the integration is off. Document on disableOnShake()
that it only turns off the SDK-wide detection.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 92fc15f. Configure here.

… show

Drives a real shake through the detector and injects a dialog that
reports itself visible and then fails to show, the way Android runs
onStart() before adding the window. Verified to fail without the
re-arm in the catch block.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@markushi
markushi merged commit d8829db into main Aug 13, 2026
70 of 72 checks passed
@markushi
markushi deleted the feat/runtime-enable-disable-shake-to-report branch August 13, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support runtime enable/disable of shake-to-report

3 participants