Skip to content

Fix secondary user SMS notification hiding sender and message#200

Open
m4pl wants to merge 3 commits into
GrapheneOS:mainfrom
m4pl:task/75-secondary-user-sms-notification
Open

Fix secondary user SMS notification hiding sender and message#200
m4pl wants to merge 3 commits into
GrapheneOS:mainfrom
m4pl:task/75-secondary-user-sms-notification

Conversation

@m4pl

@m4pl m4pl commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Closes #75

Fixed: secondary users saw a generic "New message" instead of the sender and text. The notification now shows them directly.

Also: receivers moved to Kotlin, receive/parse/notify logic split into DI collaborators, phone number formatting consolidated.

How to check on device:

  1. As owner, enable "Phone calls & SMS" for a secondary user.
  2. Switch to that user, open the app.
  3. Text your own number. The notification shows the sender and message.

@m4pl
m4pl requested review from RankoR and inthewaves July 13, 2026 10:37
@m4pl
m4pl marked this pull request as ready for review July 13, 2026 10:37
return
}

if (intent.action == Sms.Intents.SMS_RECEIVED_ACTION) {

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.

android.provider.Telephony.MMS_DOWNLOADED is not handled there, so user will not receive a notification

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I checked and couldn't find this action broadcast anywhere. Messaging sends its own SendStatusReceiver.MMS_DOWNLOADED for MMS downloads, and incoming MMS comes through WAP_PUSH_DELIVER, so this branch never fired. @inthewaves, what do you think?

) {
// The contact lookup performs a synchronous query, so resolve off the main thread.
val pendingResult = goAsync()
entryPoint.applicationScope().launch(entryPoint.ioDispatcher()) {

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.

Concurrent broadcasts can display an older SMS as the latest notification.
Every broadcast starts an independent Dispatchers.IO coroutine, so:

  1. SMS A starts a slow contacts lookup
  2. SMS B arrives later and resolves quickly
  3. B posts its notification
  4. A completes and overwrites B using the shared notification ID

}

if (intent.action == Sms.Intents.SMS_RECEIVED_ACTION) {
handleSecondaryUserSmsReceived(context, intent, entryPoint(context))

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.

Would it be more reliable to handle it in a Service instead of short-living Broadcast, given that we're querying db with unpredictable delays?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As far as I know the system gives a receiver ~10s, and a single contact lookup should finish well within that. Service/WorkManager feels like overkill here, and this worked fine before.

)
}

private fun entryPoint(context: Context): IncomingSmsEntryPoint {

@RankoR RankoR Jul 13, 2026

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.

Why not regular injection?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The receiver is created by the system, not by Hilt, so constructor injection isn't possible. The usual alternative is @AndroidEntryPoint field injection, but that requires calling super.onReceive(), and it doesn't compile because BroadcastReceiver.onReceive is abstract. So the remaining option is EntryPointAccessors to reach the Hilt graph.

@RankoR RankoR Jul 13, 2026

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.

AndroidEntryPoint

Yes, that's what I mean, not injecting the receiver itself, of course :)

but that requires calling super.onReceive()

Ah, okay

import org.junit.Assert.assertNull
import org.junit.Test

internal class SecondaryUserMessageResolverTest {

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.

Test coverage should be improved, currently tests are skipping lots of cases

@m4pl
m4pl force-pushed the task/75-secondary-user-sms-notification branch from 7f1120c to b1a4825 Compare July 13, 2026 20:55
@m4pl
m4pl force-pushed the task/75-secondary-user-sms-notification branch from b1a4825 to f9f3d8c Compare July 13, 2026 21:04
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.

SMS notifications require tap

2 participants