Skip to content

fix(mobile): stop clearing Android notifications when the badge drops to zero - #2491

Merged
DoodleBears merged 2 commits into
mainfrom
claude/project-thread-9rg7zp
Oct 21, 2026
Merged

DoodleBears merged 2 commits into
mainfrom
claude/project-thread-9rg7zp

Conversation

@DoodleBears

Copy link
Copy Markdown
Contributor

Requested by Vain · project thread

Why

#2485 passed the phone check on main 2d0bf6e (result), but it surfaced a new problem. An unread Mira DM notification disappeared in the same second as a kind=badge push, together with the secret-input request that had just been handled.

Cause: when the last pending request is resolved, the Host's badge drops to 0. The Host sends a badge push, and the app's push-session.reflect() calls setBadge(0) at the same moment. On Android, expo-notifications implements setBadgeCountAsync(0) as NotificationManager.cancelAll() (badge/BadgeHelper.kt), so every notification in the shade gets cleared, unread DMs included. reflect() itself only dismisses resolvable kinds (approval, question, private input), so the DM was removed by cancelAll.

Change outline

  • native-notifications.ts: setBadge returns immediately on Android. Android launchers count notifications themselves, and resolvable requests are still dismissed one by one by reflect(). iOS is unchanged.
  • The conversation-notifications README explains why.

Verification

  • tsc passes.
  • Not yet done: a phone check that an unread DM stays after a pending request is resolved.

Generated by Claude Code

… to zero

expo-notifications' setBadgeCountAsync(0) calls NotificationManager.cancelAll()
on Android, so resolving the last pending request also removed unread Bot
messages from the shade. Android launchers count notifications themselves, so
the app no longer sets the badge there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrtPca5pD72Gdx4CFkQdNi
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrtPca5pD72Gdx4CFkQdNi
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 34 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a941c9ac-36fd-464a-b645-bdaa4e479169
📥 Commits

Reviewing files that changed from the base of the PR and between f76a085 and ccdfaf2.

📒 Files selected for processing: 3
  • apps/mobile/modules/conversation-notifications/README.md
  • apps/mobile/src/host/native-notifications.ts
  • changes/2491-android-badge-keeps-notifications.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DoodleBears
DoodleBears merged commit 37971eb into main Oct 21, 2026
11 checks passed

Copy link
Copy Markdown
Contributor Author

Android phone result on main 37971eb (#2491): an unread DM now stays (PASS), but handled request notifications are not removed (FAIL) (Xiaomi, Android 16 / HyperOS 3, fresh isolated QA Host and store build, battery saver unrestricted and autostart on, app in the background, real Host pushes)

Evidence: 2465-android-push/phone-37971eba (commit cf3e655): 1-after-private-input-submitted.png, 2-after-app-opened.png, notification-persistence.md

Steps: (1) Mira DM reply, left unread. (2) Echo secret-input request, submitted with fake data. (3) Echo secret_cli approval, denied via the CLI. Echo replied QA-SECRET-REFUSED, and the Host sent a badge push.

Check Result
Unread Mira DM stays after the badge push PASS: the badge going to 0 no longer clears the shade
Handled secret-input and approval notifications disappear FAIL: both were still there after 60 s in the background, and still there 30 s after opening the app to the foreground

Likely cause (inferred; the release build can't be debugged): push-session reflect() removes handled notifications by reading getPresentedNotificationsAsync() data and matching it against the pending set. The posted notifications are MessagingStyle notifications rebuilt by ConversationStyle. They may no longer carry the extras where Expo stores the request data, so nothing matches. Options: keep the original extras on the rebuilt notification, or record the notification ID per itemId and cancel it directly. Also, the JS does not run on a badge push in the background, so removing these in the background may need native support.


Generated by Claude Code

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.

2 participants