Skip to content

feat(feedback): implement shake gesture detection#5150

Merged
antonis merged 40 commits intomainfrom
antonis/feedback-shake
Mar 17, 2026
Merged

feat(feedback): implement shake gesture detection#5150
antonis merged 40 commits intomainfrom
antonis/feedback-shake

Conversation

@antonis
Copy link
Contributor

@antonis antonis commented Mar 3, 2026

📜 Description

Implements shake gesture detection for the user feedback form. When useShakeGesture is enabled in SentryFeedbackOptions, shaking the device opens the feedback form.

The implementation uses the device's accelerometer (via SensorManager) with a 2.7G threshold and 1-second cooldown. A new ShakeDetectionIntegration registers lifecycle callbacks to start/stop the detector when the activity resumes/pauses.

Note: this is exposed to be used on React Native too getsentry/sentry-react-native#5754

💡 Motivation and Context

The useShakeGesture property already existed in SentryFeedbackOptions but was never wired up. This PR implements the feature. The implementation is placed here (sentry-java) rather than in each SDK separately so it can be reused by all SDKs that embed the feedback UI (React Native, Flutter, .NET MAUI, Unity).

No special permissions are required — TYPE_ACCELEROMETER is not a protected sensor. Only BODY_SENSORS requires a permission.

💚 How did you test it?

  • Tested with the sample app bc775db and verified that shaking the device opens the feedback form
  • Unit tests added for SentryShakeDetector and ShakeDetectionIntegration

📝 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. docs(android): Add shake-to-report feedback documentation sentry-docs#16792
  • 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

sentry-react-native will remove its own RNSentryShakeDetector and delegate to this class instead.

Adds SentryShakeDetector (accelerometer-based) and ShakeDetectionIntegration
that shows the feedback dialog when a shake is detected. Controlled by
SentryFeedbackOptions.useShakeGesture (default false).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (feedback) Implement shake gesture detection by antonis in #5150

Bug Fixes 🐛

  • (android) Bump epitaph to 0.1.1 by supervacuus in #5200

Internal Changes 🔧

Deps

  • Update Native SDK to v0.13.2 by github-actions in #5181
  • Bump github/codeql-action from 4.32.4 to 4.32.6 by dependabot in #5170
  • Bump dorny/paths-filter from 3.0.2 to 4.0.1 by dependabot in #5195
  • Bump actions/create-github-app-token from 2.2.1 to 3.0.0 by dependabot in #5196
  • Bump getsentry/craft from 2.23.1 to 2.24.1 by dependabot in #5197
  • Bump reactivecircus/android-emulator-runner from 2.35.0 to 2.37.0 by dependabot in #5194

Other

  • Support apps compiled against Jetpack Compose 1.10 by markushi in #5189

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

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

Generated by 🚫 dangerJS against 8456a56

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 360.38 ms 434.02 ms 73.65 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
8687935 332.52 ms 362.23 ms 29.71 ms
27d7cf8 309.43 ms 364.27 ms 54.85 ms
f064536 329.00 ms 395.62 ms 66.62 ms
abfcc92 337.38 ms 427.39 ms 90.00 ms
ae7fed0 293.84 ms 380.22 ms 86.38 ms
d15471f 361.89 ms 378.07 ms 16.18 ms
1df7eb6 397.04 ms 429.64 ms 32.60 ms
9fbb112 401.87 ms 515.87 ms 114.00 ms
6405ec5 310.88 ms 354.56 ms 43.69 ms
62b579c 318.48 ms 367.71 ms 49.24 ms

App size

Revision Plain With Sentry Diff
8687935 1.58 MiB 2.19 MiB 619.17 KiB
27d7cf8 1.58 MiB 2.12 MiB 549.42 KiB
f064536 1.58 MiB 2.20 MiB 633.90 KiB
abfcc92 1.58 MiB 2.13 MiB 557.31 KiB
ae7fed0 1.58 MiB 2.12 MiB 551.77 KiB
d15471f 1.58 MiB 2.13 MiB 559.54 KiB
1df7eb6 1.58 MiB 2.10 MiB 532.97 KiB
9fbb112 1.58 MiB 2.11 MiB 539.18 KiB
6405ec5 1.58 MiB 2.12 MiB 552.23 KiB
62b579c 0 B 0 B 0 B

Previous results on branch: antonis/feedback-shake

Startup times

Revision Plain With Sentry Diff
90c01e9 314.38 ms 370.51 ms 56.13 ms
395b61e 318.16 ms 373.86 ms 55.70 ms
2052d5f 331.52 ms 401.71 ms 70.19 ms
dc10a90 307.28 ms 359.06 ms 51.78 ms
d743634 404.69 ms 507.35 ms 102.66 ms
3a14925 327.15 ms 380.52 ms 53.37 ms
ba57364 317.45 ms 360.35 ms 42.90 ms
1229590 312.98 ms 355.29 ms 42.31 ms
c52d557 383.26 ms 436.00 ms 52.74 ms
58a9026 330.31 ms 370.45 ms 40.13 ms

App size

Revision Plain With Sentry Diff
90c01e9 1.58 MiB 2.29 MiB 727.37 KiB
395b61e 1.58 MiB 2.29 MiB 727.32 KiB
2052d5f 1.58 MiB 2.29 MiB 726.85 KiB
dc10a90 0 B 0 B 0 B
d743634 0 B 0 B 0 B
3a14925 1.58 MiB 2.29 MiB 727.39 KiB
ba57364 1.58 MiB 2.29 MiB 727.15 KiB
1229590 0 B 0 B 0 B
c52d557 0 B 0 B 0 B
58a9026 1.58 MiB 2.29 MiB 727.33 KiB

antonis and others added 2 commits March 4, 2026 13:08
- Add volatile/AtomicLong for thread-safe cross-thread field access
- Use SystemClock.elapsedRealtime() instead of System.currentTimeMillis()
- Use SENSOR_DELAY_NORMAL for better battery efficiency
- Add multi-shake counting (2+ threshold crossings within 1.5s window)
- Handle deferred init for already-resumed activities
- Wrap showDialog() in try-catch to prevent app crashes
- Improve activity transition handling in onActivityPaused
- Mark SentryShakeDetector as @ApiStatus.Internal
- Add unit tests for SentryShakeDetector and ShakeDetectionIntegration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@antonis antonis marked this pull request as ready for review March 4, 2026 13:12
@antonis antonis requested a review from alwx March 4, 2026 13:14
… shakes

Track dialog visibility with an isDialogShowing flag that is set before
showing and cleared via the onFormClose callback when the dialog is
dismissed. Double-checked on both sensor and UI threads to avoid races.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… growth

Save the user's original onFormClose once during register() and restore
it after each dialog dismiss, instead of wrapping it with a new lambda
each time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ck flag

If showDialog silently fails (e.g. activity destroyed between post and
execution), isDialogShowing would stay true forever, permanently
disabling shake-to-feedback. Reset it in onActivityPaused since the
dialog cannot outlive its host activity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ActivityDestroyed

AlertDialog survives pause/resume cycles (e.g. screen off/on), so
resetting isDialogShowing in onActivityPaused allowed duplicate dialogs.
Move the reset to onActivityDestroyed where the dialog truly cannot
survive.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…back on error

- Only reset isDialogShowing in onActivityDestroyed when it's the
  activity that hosts the dialog, not any unrelated activity.
- Restore originalOnFormClose in the catch block when showDialog throws.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: LucasZF <lucas-zimerman1@hotmail.com>
@sentry
Copy link

sentry bot commented Mar 9, 2026

Sentry Build Distribution

App Version Configuration
SDK Size 8.34.1 (1) release

The onFormClose lambda was reading previousOnFormClose field at dismiss
time. If onActivityResumed or onActivityDestroyed already restored and
nulled the field, the lambda would overwrite onFormClose with null. Now
captured as a local variable at dialog creation time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sentry
Copy link

sentry bot commented Mar 9, 2026

Sentry Build Distribution

App Version Configuration
SDK Size 8.34.1 (1) release

When close() is called while a dialog is showing, lifecycle callbacks
are unregistered so onActivityDestroyed cleanup won't fire. Restore
previousOnFormClose and reset dialog state in close() to prevent
the callback from being permanently overwritten.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sentry
Copy link

sentry bot commented Mar 9, 2026

Sentry Build Distribution

App Version Configuration
SDK Size 8.34.1 (1) release

@antonis antonis requested a review from romtsn March 9, 2026 16:41
antonis and others added 2 commits March 16, 2026 14:39
Add proactive activity validity check inside the runOnUiThread lambda
to avoid hitting the catch block with a BadTokenException when the
activity becomes invalid between the shake callback and UI execution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Member

@romtsn romtsn left a comment

Choose a reason for hiding this comment

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

Great effort, thanks for addressing many PR reviews! There's only one left for reusing the handler thread, but LGTM otherwise

Copy link

@cursor cursor bot left a comment

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.

Follow the established defensive pattern used by all other Android
integrations instead of an unchecked cast that could throw
ClassCastException if a hybrid SDK passes a different options type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@antonis antonis merged commit 28b6988 into main Mar 17, 2026
71 of 72 checks passed
@antonis antonis deleted the antonis/feedback-shake branch March 17, 2026 13:34
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.

4 participants